views:

535

answers:

5

In my application, I've got several ViewModels that have a single service (repository, DAO, whatever), let's call it the WidgetService, injected into them.

Let's say that one of these ViewModels is a listing of all of a users widgets. Another could be the ViewModel for editing/creating a single one of these Widgets.

The user can view the list of widgets in the WidgetListView backed by a WidgetListViewModel and click a button to add a new widget. To create this new Widget, a CreateWidgetViewModel is new'd up and injected into the DataContext of some UserControl/Window thus, through the magic of DataTemplates displaying the CreateWidgetViewModel in a CreateWidgetView. Also, the newing up of the CreateWidgetViewModel does not necessarily happen within the scope of the WidgetListViewModel.

When the WidgetListViewModel it was injected with an instance of the WidgetService . The CreateWidgetViewModel was injected with this same WidgetService instance.

Now, when the user clicks save in the CreateWidgetView the Save method on the WidgetService will be invoked and the widget will be persisted. Now the WidgetListViewModel needs to be notified that there is a new Widget to be displayed!

The long buildup leads to this question: How do I let the WidgetListViewModel know that it needs to display the new Widget?

I've seen a Video in which a guy from Microsoft does this sort of thing using an event on the service that the ViewModel subscribes to. However, the downfall of this is that if the service outlives the viewmodel, then the viewmodel wont get GC'd until the service is GC'd. I could add IDisposable to the ViewModel. But then when/how to call Dispose when the ViewModel is only represented in the UI via DataTemplates?

Does anyone have any suggestions regarding this?

To clarify, I'd say my interpretation of MVVM most closely resembles Josh Smith's. At least in as much as my MVVM architecture pretty closely matches that found in the Crack.Net source.

+1  A: 

Ok, given there's been no answers to this yet I thought I'd give it a try, but I'm not an expert on MVVM.

Events seem to be the way to go with this. However as you pointed out there can be a memory leak if the service outlives the ViewModel. The best way to deal with this is with a weak event listener.

Weak Events allow you to hook up to an event with a weak reference so that if the source object is GC'd then the source is not kept alive by the event handler.

Cameron MacFarland
I think I'm going to consider doing the weak events pattern. I still don't think it's ideal, but it seems easy to implement. Thanks.
dustyburwell
A: 

I used the Observer Pattern (aka the publish/subscribe pattern) to solve this same problem. I made a class I called EventAggregator which had all shared methods and data members. I could register for an event on the WidgetListViewModel and publish a "Widget Created" event in the CreateWidgetViewModel. You can either have WidgetListViewModel implement IDisposable (better) to unregister your event or you can just unregister it in the Finalize method. It worked out pretty well and the best part is that the two view models didn't need to have any idea about each other.

For something more complicated or if you need to support version differences between the service and your app you could implement a ModelView which would handle this sort of thing making your applications's pattern M-MV-VM-V. It might seem a little overkill but it can make certain classes of problems much easier to maintain. I know I've had a few projects where I wish I had inserted an MV because the crosstalk between VMs and undo code has just gotten ridiculous.

Bryan Anderson
+1  A: 

Use Prism's (http://www.codeplex.com/CompositeWPF) EventAggregator which uses the publisher-subscriber pattern, providing lose coupling between the target and source elements. Perfect for exactly the scenario you describe.

PaulJ
A: 

There are several options:

  1. Use ObservableCollection - this is probably the simplest option, but you have to have some sort of "master" collection in the model and have the UI bind to this collection directly, this may not be "clean" MVVM architecture but its probably the easiest way to get the job done.

  2. Use event and make sure you clean up after yourself, not easy to do in MVVM.

  3. Use some middleman to automatically clean the events (as others suggested) but don't write your own, there are a lot of pitfalls in this, WPF has a built-in class that does that but I forgot the name (if someone remembers the name please leave a comment).

  4. Do periodical refreshes, have you ViewModel class refresh the list every X seconds, this is the only way to get the updates without some sort of notification mechanism you have to manage.

Nir
A: 

I agree with Cameron to use the WeakEvent pattern. I've created a base class for the ViewModel (in my example I use the name PresentationModel) that supports the WeakEvent pattern.

You might find my example project useful: http://www.codeplex.com/CompositeExtensions

jbe