I just want to ask if it's OK to access the ViewModel's data in the View backend?
Basically I just need a check to see if a ViewModel's property is set (which gets set when the user selects something), and if it's not I'll just redirect the user to another View telling him he needs to select something first. Is this a poor-design practice or is it OK, just for a minor check like this? Really don't want to implement a static class and extrapolate the data to it, and check it instead.
Another question tightly related to this, is can I call a method from the View (when the View is closing), that unregisters that particular ViewModel from the IoC container (this ViewModel isn't singleton). The alternative is to send a message from the View to the ViewModel when the View is closing, and when the ViewModel gets that message it unregisters itself. The problem I'm trying to solve with this is that, every time that ViewModel is requested it has to be a new one, but my IoC container caches them, making my program a memory hog. All of the ViewModels get released on application exit, meaning x ViewModels will still exist in the cache even though they're most likely not needed.
Basically I just need a check to see if a ViewModel's property is set (which gets set when the user selects something), and if it's not I'll just redirect the user to another View telling him he needs to select something first. Is this a poor-design practice or is it OK, just for a minor check like this?
It does not seem to be wrong to check the value of some ViewModel property and reflect the changes on the View side. The View state could be "bound" to the ViewModel state by the WPF data binding mechanism: Binding, Triggers (Trigger, DataTrigger, EventTrigger), Commands (including EventToCommand), etc.
But sometimes it is useful to handle ViewModel state change by the ViewModel itself using UI Services. For example, IWindowService interface can be introduced to allow to open windows from the context of the ViewModel implementation.
Another question tightly related to this, is can I call a method from the View (when the View is closing), that unregisters that particular ViewModel from the IoC container (this ViewModel isn't singleton).
...
The problem I'm trying to solve with this is that, every time that ViewModel is requested it has to be a new one, but my IoC container caches them, making my program a memory hog. All of the ViewModels get released on application exit, meaning x ViewModels will still exist in the cache even though they're most likely not needed.
It seems to be strange that the described dependency container "cache effect" exists when the registration is specified as "resolve per call behavior" (not "singleton behavior"). Please check that the registration is specified as "resolve per call behavior" (for example, PerResolveLifetimeManager in terms of Unity Container Lifetime Managers).
Update
The ViewModel lifetime problem exists because SimpleIoC container is used.
I would like to recommend using another dependency injection container (with appropriate lifetime management) to make the implementation less complex and error-prone.
But, if there is a strong need to use SimpleIoC container, some kind of the ViewModel lifetime management can be implemented using:
SimpleIoc.Default.GetInstance<ViewModel>(key); method call to resolve an instance of ViewModel;
SimpleIoc.Default.Unregister(key); to un-register the instance when it is no longer needed (Closed event, etc).
The implementation can be found here: answer #1, answer #2.
Related
I often have the situation that I need to pass a linq2sql object from one WPF window to another one.
For example I have a window with a list of linq2SQL objects. The list is bound from a public declared DataContext in the "Window_Loaded"-event. With a double click on one of these items a second window opens and the object can be edited. While opening the selected object is passed to a property of the second window. After the user has made some changes he decides to discard the changes and closes the second window.
Now because the input fields are bound directly to the Linq2SQL object the changed values are still present.
What is the best practice in this situation? Is it better to pass a newly created object from a new created DataContext to the second window? Then I have to somehow refresh the list on the first window when the changes are wanted.
Or can I use the already bound object from the list of objects from the first window and pass it directly to the second window?
I know that I can refresh the object when I have to reload the object
DB.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, MyObject);
What is the best practice?
The question is more general and touches the important issue: what lifetime policy best suits the linq2sql datacontext in different types of applications.
In case of a web application, this question has a simple answer: the "per-httprequest" lifetime policy is the most convenient.
In your case, a WPF application, there are two approaches I am aware of:
in a "per-the-lifetime-of-the-application" policy you would create a single data context for the lifetime of your application. Although technically this works, there are potential issues with the memory consumption - as the application retrieves more and more data, the first level cache in the data context grows without control and could possibly just run out of resources at some point
in a "per-presenter (view)" policy you create a new data context in each of your presenter (view model) (or view, if you don't follow mvvm) which means that two different views do not share the same context. I'd say this is recommended approach, there are no risks of unwanted resource issues, however, you need an additional mechanism to pass events between views so that views could be refreshed when the data changes.
Note, that all your business logic should be unaware of the actual policy. To do so, let your data context be injected (by constructor for example) to any class that uses it. Depending on the actual policy, a proper context is injected into a business class. This way, you could even change the lifetime management policy someday with no need to refactor your business code.
I'm new to MVVM and WPF itself. I need to do some prototyping in WPF and reached conceptual question.
Suppose you have server which sends you data. Regardless of whether you displaying that currently or not you need to store it in cache, this is your "real data" and at some time you will need to put it on UI (when user opens particular screen), this is your viewmodel.
My question is quite obvious - should I bind UI to a real data stored in some service or should I do a viewmodel wrapper around that data and bind to it?
In the first case I receive "The calling thread cannot access this object" exceptions unless I use Dispatcher, but calling Dispatcher in model doesn't look right
In the later case I will need to:
copy 90% of the data from "real model" to wrapper
manually watch changes in underlying "real data" to update viewmodel which in case implements INotifyPropertyChanged.
What is the correct way?
The way it is most appropriate, is to have your ViewModel pretty similar to your View's needs. It means if your View has a list, then you most likely will need at lease 2 properties on your ViewModel, one for the ItemSource and the other for the selected Items.
Regarding the real data stored, I would say, put it being accessed by your service. Maybe you use the WPF or Silverlight, so you will be protecting your true physical data. And may exchange, just the proper information the view requires.
I hope it helps. If you would like to share some arquitectural aspects of your project, we might give you more advices.
I do prefer to have the Data cache in what I call the 'service layer' (the client side code that actually interacts with the server via WCF or whatever communications mechanism).
the data cache is actually several List<T> and I do not listen for change notifications in there, because that is actually not needed.
Instead, you consume these 'client side services' from your ViewModels, and retrieve the List<T> and store the items in the ViewModel in an ObservableCollection<T>. This way you can have two way binding from the View to the ViewModel, with no need for the View to interact with the 'lower level' data cache stored in the 'service layer'.
You do not need to use the Dispatcher when performing ViewModel operations, and therefore this is a better scalable approach because you can do whatever multithreading is needed to retrieve the data.
What i did
I have HomeViewModel and SellsViewModel.
In the HomeViewModel, I have property "SellID"
In the constructor of SellViewModel, i am able to Resolve reference of HomeViewModel and stored it in m_objHomeViewModel variable in SellViewModel
In the XAML of SellViewModel, i have a textbox which shows "SellID", this textbox is bound to "m_objHomeViewModel.SellID"
What i am getting doing this
Doing this, whenever user selects difference "Sell" on HomeViewModel, automatically my SellViewModel picks it up and shows changes in SellView.
Question
As XAML textbox in SellView is bound to a property in HomeViewModel, changes are getting reflected on UI immediately
But i am not able catch any event (Such as property change) in SellViewModel, catching such event i want to load other values for the selected "SellID" from database.
I am not using Event Agreegator. If used, i can easily subscribed to event in SellViewModel published by HomeViewModel
Q1: How to do it without using Event Agreegator?
Q2: If in XAML, TextBox is bound to property m_objHomeViewModel.SellID, will it create memory leakage?
Q3: If in the HomeViewModel, i get reference to SellViewModel (Using container.resolve) and call a public property or method of SellViewModel whenever "SellID" property in HomeViewModel is modified. Is it a good programming practice? Here i think it will create tight coupling between HomeViewModel and SellViewModel
Please suggest on this...
Regards
A1: If I understand your design, your SellVM will need to manually subscribe to the PropertyChanged event of your HomeVM. If the SellId property of your HomeVM raises PropertyChanged, then your SellVM will see that and respond accordingly.
A2: Without seeing the entire application, simply databinding to a property won't cause a memory leak. As long as the UI is displayed, the HomeVM will be in memory, but .NET does a pretty good job of recognizing when it is no longer needed and cleaning up the memory. The answer to this is highly dependent on your overall design, but the simple act of binding the SellID from the HomeVM through the SellVM won't, on its own, cause a memory leak.
A3: This sounds a little strange - Without understanding the full architecture, it seems that the SellID should belong to the SellVM, and when the users switches SellID, the HomeVM loads the SellVM with the appropriate SellID. This seems more OO and allows you to separate concerns. This way everything about the "Sell" (sale?) is encapsulated in the SellVM and the HomeVM is strictly responsible for coordination (loading the correct child VMs). But this is based on what little I can gather about your overall design.
My MVVM app has a number of views that inherit from a base user control, which exposes an "ID" property. In the XAML this is bound to an ID property on the view's underlying view model, simply:
Id="{Binding Path=Id}"
The view model implements INotifyPropertyChanged, and its ID is set in the constructor. The ID is used to uniquely identify each view/view model, and is primarily used by a "desktop manager" to manage the user controls within the main window, rather like an MDI app. When my app starts I instantiate the various view models and their views, and assign the view models to the views' DataContext. I then pass the views to the desktop manager which places them on its canvas, positions them, etc.
The problem I have is that the view's ID is still null at this point, and only seems to get bound to the data context some time later (when the UI is rendered perhaps?). I have tried forcing the binding like this, but it doesn't help:-
var bindingExpression = widget.GetBindingExpression(DesktopElement.IdProperty);
bindingExpression.UpdateTarget();
It's not the end of the world, as I can pass the desktop manager my view and the ID from the view model, but it feels a little hacky. I was curious to know at what point in the control/window lifecycle the binding occurs, and whether there was some other way to force the binding to happen?
Thanks in advance
Andy
In order to understand how bindings are transferred, you need to understand the Dispatcher. Basically, it is a priority queue. Things like layout, bindings, rendering, input, etc. are placed in the queue at different priorities.
Now, from the sound of it, you never yield execution back to the Dispatcher. This means that Binding values can't transfer (when you manually call UpdateTarget you are just scheduling this on the Dispatcher). So, in short, you need to let the Dispatcher execute the queued operations before you finish initializing.
The easiest way to do this is to call BeginInvoke at a lower DispatcherPriority on a method to finish initialization. Because of the nature of how the layout system works, it can be tricky sometimes to pick the right priority, but you'll probably be okay if you go with DispatcherPriority.Loaded.
My suggestion would be to have an interface that your View Models implement, which exposes the Id property. You can then have your Desktop Manager grab the Id from the DataContext by casting it to the appropriate interface. This is likely a cleaner separation of responsibilities, as your Desktop Manager should probably know as little about the concrete View as possible (for the sake of testability.)
I have a WPF application based on PRISM that utilizes the MVVM pattern.
I have noticed that occasionally my view models, views and everything connected to them will hang around long after their intended lifespan.
One leak involved subscribing to CollectionChanged on a collection belonging to an injected service, another involved not calling the Stop method on a DispatcherTimer, and yet another required a collection be cleared of it's items.
I feel using a CompositePresentationEvent is probably preferable to subscribing to CollectionChanged, but in the other scenarios I am leaning towards implementing IDisposable and have the views call the Dispose method on the view models.
But then something needs to tell the view when to call Dispose on the view model, which gets even less attractive when the complexity of the views increase, and they start including child views.
What do you think is the best approach to handling view models, to ensure they don't leak memory?
Thanks in advance
Ian
I can tell you that I've experienced 100% of the pain you have experienced. We are memory leak brothers, I think.
Unfortunately the only thing I've figured out to do here is something very similar to what you are thinking.
What we've done is create an attached property that a view can apply to itself to bind a handler to the ViewModel:
<UserControl ...
common:LifecycleManagement.CloseHandler="{Binding CloseAction}">
...
</UserControl>
Then our ViewModel just has a method on it of type Action:
public MyVM : ViewModel
{
public Action CloseAction
{
get { return CloseActionInternal; }
}
private void CloseActionInternal()
{
//TODO: stop timers, cleanup, etc;
}
}
When my close method fires (we have a few ways to do this... it's a TabControl UI with "X" on the tab headers, that kind of thing), I simply check to see if this view has registered itself with the AttachedProperty. If so, I call the method referenced there.
It's a pretty roundabout way of simply checking to see if the DataContext of a View is an IDisposable, but it felt better at the time. The problem with checking the DataContext is you might have sub view models that also need this control. You'd either have to make sure your viewmodels chain forward this dispose call or check all of the views in the graph and see if their datacontexts are IDisposable (ugh).
I sort of feel like there is something missing here. There are a few other frameworks that attempt to mitigate this scenario in other ways. You might take a look at Caliburn. It has a system for handling this where a ViewModel is aware of all sub view models and this enables it to automatically chain things forward. In particular, there is an interface called ISupportCustomShutdown (I think that's what it's called) that helps mitigate this problem.
The best thing I've done, however, is make sure and use good memory leak tools like Redgate Memory Profiler that help you visualize the object graph and find the root object. If you were able to identify that DispatchTimer issue, I imagine you are already doing this.
Edit: I forgot one important thing. There is a potential memory leak caused by one of the event handlers in DelegateCommand. Here's a thread about it on Codeplex that explains it. http://compositewpf.codeplex.com/WorkItem/View.aspx?WorkItemId=4065
The latest version of the Prism (v2.1) has this fixed. (http://www.microsoft.com/downloads/details.aspx?FamilyID=387c7a59-b217-4318-ad1b-cbc2ea453f40&displaylang=en).
My findings so far...
In addition to PRISM, Unity, WPF and MVVM we are also using Entity Framework and the Xceed data grid. Memory profiling was done using dotTrace.
I ended up implementing IDisposable on a base class for my view models with the Dispose(bool) method being declared virtual allowing sub classes the chance to clean up as well.
As each view model in our application gets a child container from Unity we dispose it as well, in our case this ensure that EF's ObjectContext went out of scope. This was our major source of memory leaks.
The view model is disposed within an explicit CloseView(UserControl) method on a base controller class. It looks for an IDisposable on the DataContext of the view and calls Dispose on it.
The Xceed data grid seems to be causing a fair share of the leaks, especially in long running views. Any view that refreshes the data grid's ItemSource by assiging a new collection should call Clear() on the existing collection before assigning the new one.
Be careful with Entity Framework and avoid any long running object contexts. It's very unforgiving when it comes to large collections, even though you have removed the collection if tracking is turned on, it will hold a reference to every item in the collection even though your no longer hanging on to them.
If you don't need to update the entity retrieve it with MergeOption.NoTracking, especially in long lived views that bind to collections.
Avoid views with a long life, don't hold onto them within a region when they are not visibile, this will cause you grief especially if they refresh their data at regular intervals when they are visible.
When using CellContentTemplates on the Xceed Column don't use dynamic resources as the resource will hold a reference to the cell, which in turn keep the entire view alive.
When using CellEditor on the Xceed Column and the resource is stored in an external resource dictionary add x:Shared="False" to the resource containing the CellEditor, once again the resource will hold a reference to the cell, using x:Shared="False" ensures you get a fresh copy each time, with the old one being removed correctly.
Be careful when binding the DelegateCommand to items within the Exceed data grid, if you have a case such as a delete button on the row which binds to a command, be sure to clear the collection containing the ItemsSource before closing the view. If you're refreshing the collection you also need to reinitialize the command as well as the command will hold a reference to each row.