views:

135

answers:

1

I have an existing Silverlight 4 application that I am attempting to convert to use the locator pattern and the MVVM-Light library.

My understanding is that the MvvmLocator class keeps a reference to each view model and allows you to bind the DataContext of each view to an appropriate ViewModel in the locator.

My application uses a navigation frame and hence each page in the app is a UserControl that gets loaded into the Content frame.

I can see how easy it is to bind each page view to the appropriate ViewModel in the locator, but my problem is that I have other UserControls with their own view models that get re-used in multiple contexts and it would cause problems if each instance of the control got bound to the same ultimate view model instance.

For example, I have a search page that consists of 2 user controls. The first is a search parameter control that contains several inter-dependent combo boxes and a search button. The second is the results grid itself. The view model of the page that contains these 2 controls handles the communication between them. The problem is that this search control gets used on other pages as well, and having them all use the same view model instance would cause all kinds of headaches. So, using the normal "DataContext={Binding ProductSearch, Source={StaticResource Locator}}" seems out of the question...

Has anyone else run into this or have any bright ideas how to solve it? I'm thinking maybe I could modify the locator to create a new instance of the view model for each page where the control is used. Otherwise, I could just force a cleanup on every page transition, but then I wouldn't be able to save state between pages.

I am new to the whole Silverlight and MVVM world, so maybe I am missing something about how this all should be structured or have painted myself into a corner. I'm just not sure. I would definitely welcome any suggestions.

+1  A: 

Your main problem is the fact that the Silverlight navigation framework always creates a new instance of a view when you navigate to it. You can override this behavior using INavigationContentLoader and storing instances of your views to be re-used.

Some examples of using INavigationContentLoader are David Poll's Opening up Silverlight 4 Navigation: Introduction to INavigationContentLoader or Mike Taultry's Silverlight 4 Rough Notes: Taking Control of Navigation blog posts. These posts only show how to create your own content loader; using it to reload existing views is up to you.

Matt Casto
I had no idea that interface existed. Thanks! That helps in a number of ways. But, I still had the question of how to bind the DataContext of a reusable UserControl. What I was thinking was that I create instances of the necessary view models as members of the view model for the top-level page and then bind that to the UserControls when they are referenced in a page. At least I could do that for page view models that require child view model instances as parameters in the constructor. Does that make sense?
I think that's a good solution as long as you're okay with your child UserControl views being recreated each time. If you instead create a reference to view, then you won't have to worry about re-using ViewModels. Also, you can modify the ViewModelLocator to return a new instance each time it requests a particular ViewModel to make sure your views don't accidentally re-use the ViewModel.
Matt Casto
I'm not sure I understand your point about creating a reference to a view. For example, let's say I have a view model with the following constructor: SearchPageVM(SearchControlVM svm, ResultsControlVM rvm). If I have the locator construct an instance of this, I would need to bind the controls in such a way that they would pick up these instances as their DataContext. On the other hand, if I have the UserControls create the VM instances, I don't see a way to get this to the page VM instance created by the locator unless I change all my constructors and initialize the sub-view VM's elsewhere.
Ah, I had assumed that you were using an IoC container (such as Ninject or Unity) in your locator to automatically provide your child VMs.
Matt Casto
Yeah. I wish :) That would have been nice in retrospect, but it's too big a change to make at the moment. Perhaps a little further down the road. Thanks very much for your suggestions! I got the page caching thing working, just a few wrinkles to iron out.