SimpleIOC And The Messenger Service In MVVM Light
The SimpleIoc addition in the most recent version of MVVMLight is a
great add and really simplified the ViewModelLocator across all of the
platforms supported in this framework.
If you are not familiar with MVVM Light or what you types of project platforms it supports please go to http://mvvmlight.codeplex.com or www.galasoft.ch/mvvm to learn more.
However if you are using the Messenger Service in MVVM Light to perform a set of actions to do the following:
- User takes an action
- Application changes views
- Application send message to display or load data
Lets look at the ViewModelLocator in the new version:
public class ViewModelLocator
{
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (ViewModelBase.IsInDesignModeStatic)
{
SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
}
else
{
SimpleIoc.Default.Register<IDataService, DataService>();
}
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<SecondViewModel>();
}
/// <summary>
/// Gets the Main property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
}Notice that in comparison to what you may have seen in the past version,
there is a single property to the ViewModel and a simple line in the
constructor here to register the ViewModel with the Ioc Container and
that is it.
The property for the ViewModel is Lazy, meaning that it is loaded on
demand and is a singleton. You can create multiple instances by passing
in a key upon creation, but for this example I'll keep it simple.
Given the scenario above you will get the result of the secondary view
not getting the message sent event though you have registered the
message with the Message Service and have an action ready to handle it.
BUT the second time through it's fine and operates as it should. What
has happened?
Very simply, the examples you have seen in the past very rarely ever
cover situations in the real world nor do they ever go far enough to
look at the overloads in the constructor etc.
What has happened here is that the ViewModel MUST exist first in
order to take action on the message. Moreover, the Messenger Service in
MVVM Light does not operate like a Service Bus or Message Queue where
the messages stay there until they are read. It is more similar to
Events, a fire and forget model.
In order to alleviate said problem, simple pass in "true" to the
Register call in the SimpleIoc to create the instance of the ViewModel
immediately and go on with your coding.
SimpleIoc.Default.Register<SecondViewModel>(true);The previous version of MVVM Light created all of the ViewModels immediately, although not too much of an issue; there are instances where a user may not go to every view in the application and the idea here is to only load what is needed and keep the View and ViewModels loaded in memory when necessary.
If you have questions please comment and/or contact me on twitter @spboyer
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)





Comments
Shayne Boyer replied on Sat, 2012/10/20 - 11:13am
Somebody asked me on twitter how to create a unique instance of the ViewModel each time, so here is the quick info on that.
public ViewModelName VMName(Guid guid)
{
get
{
return ServiceLocator.Current.GetInstance<ViewModelName>(guid);
}
}
Then when you create/request is the syntax is ViewModelLocator.VMName(new Guid())
Olivier Dahan replied on Sat, 2012/12/01 - 9:47am
in response to:
Shayne Boyer
This is a good solution but unfortunately it breaks the blendability.
When you create the View, the VM is automatically set in Xaml using the ViewModelLocator.
If you create the view and then use the given trick and set manually the DataContext of the View, during a short time the View is attached to the VM supplied by the Locator, this is not clean and can have side effects.
And if you suppress definitively the DataContext binding in the View, you loose the design time data and the blendability (and intellisence can't no more check other bindings in the view).
This is really a big problem in MVVM Light.
This is not important in WinRT or WP7/8 because apps in these models are fullscreen, so it is very rarely usefull to create a second instance of the same VM. But in LOB apps (with WPF mostly) it is a common need to be able to display 2 or 3 views of the same nature (Products, Customers...) that have to be compared by the user.
MVVM Light and the way it is implementing IoC does not suit the need. This is a shame because I love MVVM Light and use it since a long time, but for serious apps, there are a few problems like this one. And unfortunately tricks does not solve the latters.
Shayne Boyer replied on Mon, 2012/12/03 - 9:07am
in response to:
Olivier Dahan
I would suggest putting a comment in reference to the issue you mention here on the MVVMLight codeplex site. I do agree it is an issue with the when it comes to WPF given the solution I presented, but the Q&A was in the context of developing Windows Store Apps, apologies for not clarifying that.
Thanks for the comments.