ViewModel Being Created Twice

Jul 28, 2011 at 12:23 AM

Hi Tony

I've been working on a problem and after a very long journey realised that because I've added my page to the NavigationGrid next to the home hyperlink my page's ViewModel is being created twice - once when the application starts and then again when I click on my page's hyperlink. Is this the way things are meant to work with the Locator? My ViewModel (ViewModelDetailBase) creates a new entity when it is created (rather than having one pased in) as it is one of the starting points for my application, but the first instance that is created when the application starts never gets its values set. When domainContext.SubmitChanges is being called there are therefore two entities to try and save - one valid and one not. The invalid entity causes an exception of course.

Very grateful for your thoughts on this!

Cheers - Graham

Jul 31, 2011 at 11:50 PM

The way the ViewModelLocator works is that it exposes a property which creates a ViewModel on demand.  Most of the time you want the lifetime of a ViewModel to be tied to the View that creates it.  When the View gets garbage collected, its ViewModel gets collected with it, which avoids some potential memory leaks. (This is done when you use the mvvmlocator code snippet.)

However, there are times when you might want the View and ViewModel to stick around.  For example, you want the view to be exactly in the same state it was when the user navigated away from it.  In this case, you should set the NavigationCache property (I think that's what it's called) on the view so that it stays in memory.\

In terms of your situation, I'm having difficulty picturing what you're trying to accomplish. If you want one instance of a ViewModel to remain in memory, I would suggest you replace the code in the locator that was created with the mvvmlocator snippet with a standard property using the propfull code snippet.  Then every time you reference the ViewModel property on the locator, you would be getting the same instance.

Hope this helps.

Cheers,

Tony

Aug 1, 2011 at 8:10 AM

Thanks very much for your reply about this. Just to try and clarify, what is happening is that any Views that are hooked up to the NavigationGrid area of the MainPage (for example in the SimpleMvvm-Main part 3 code you have 'products' hooked-up in addition to 'home') are having instances of their ViewModels created at application startup. Is this the expected behaviour? If we have lots of links in the NavigationGrid area do we really want instances of all their ViewModels to be created on application startup?

Apart from the performance issue some applications might be unaffected by this. However for my specific implementation of one particular ViewModel it has a nasty side effect as I describe above. I'm keen to understand whether having ViewModels created at application startup is expected behaviour and I need to code around it or whether this unintentional and needs some sort of fix.

Cheers - Graham

Aug 1, 2011 at 1:59 PM
No, Normally ViewModels should not be created at application startup. A ViewModel should be created only when the View is instantiated, because the View's DataContext is bound to the ViewModelLocator's property, which only creates the ViewModel in the property getter. If it would help, feel free to send me the project in which ViewModels are created at startup, and I can try to see why that is taking place. My email is: tony@tonysneed.com.

Cheers,
Tony
Aug 1, 2011 at 2:12 PM

Hi Tony

It's not just my project - setting a break point at "public ProductListViewModel ProductListViewModel" in "public class InjectedViewModelLocator" on your SimpleMvvm-Main part 3 example shows ProductListViewModel being instantiated at startup.

Cheers - Graham

Aug 1, 2011 at 4:14 PM
Sorry, I didn't realize you were talking about the InjectedViewModelLocator. There is a line of code in the constructor of the InjectedViewModelLocator that is causing the ViewModel property getter to be invoked.

// Verify service agent creation
Debug.Assert(this.ItemListViewModel != null,
string.Format("No IItemListServiceAgent has ServiceAgentExport with AgentType = {0}", agentType));

Just comment out the Debug.Assert and it will no longer call the property getter. :-) The statement is just a sanity check to make sure you did not forget to put the ServiceAgentExport attribute on the service agent.

Cheers,
Tony
Aug 3, 2011 at 8:25 AM

Hi Tony

What an idiot I am! Apologies for the page 1 error :).

Cheers - Graham