There are numerous frameworks out there that provide mechanisms for instantiating view models. Long again, when I first started building XAML based applications and became familiar with MVVM, I stepped through a number of different ways of creating and wiring up view models. In this post I’m going to show a very basic implementation of a locator to instantiate view models. Into the Core library I will add a ViewModelLocator class which exposes a property, Main, that will return a new instance of the MainViewModel.
public class ViewModelLocator
{
public MainViewModel Main
{
get { return CreateViewModel<MainViewModel>(); }
}private T CreateViewModel<T>() where T:new()
{
return new T();
}
}
I’m going to want a single instance of this class to be created and kept around for the duration of my application’s lifecycle. One option would be to instantiate it within my ApplicationCore class I introduced previously. However, I actually want the instance of the ViewModelLocator to be accessible via XAML, so for this reason it makes more sense to instantiate it as a XAML resource. In the WPF and Universal (Win/WP8.1) applications I can simply add this to the app.xaml file to the Application.Resource element.
<Application.Resources>
<core:ViewModelLocator x_Key=”Locator” />
</Application.Resources>
In the MainWindow (WPF) and MainPage (Universal) I can now specify the DataContext in the opening element, removing the need to create the MainViewModel in code in the codebehind file. Eg
<Window x_Class=”RealEstateInspector.Desktop.MainWindow”
“>“
“>“
DataContext=”{Binding Main, Source={StaticResource Locator}}” >
The current implementation of Xamarin.Forms doesn’t seem to support creating Application resources in XAML. However, by tweaking the App constructor, I can add an instance of the ViewModelLocator:
public App()
{
Resources = new ResourceDictionary();
Resources.Add(“Locator”, new ViewModelLocator());MainPage =new MainPage();
}
The syntax in the MainPage of the XForms application is similar except BindingContext replaces DataContext:
BindingContext=”{Binding Main, Source={StaticResource Locator}}”
There seems to be a quirk in XForms at the moment in that the Binding expression calls to the Main property repeatedly – since it gets a different instance of the MainViewModel back each time, it ends up in an endless loop trying to get a consistent value. To prevent this, we can add a view model dictionary to the ViewModelLocator and change the behaviour to always return the same instance of the view model.
private readonly Dictionary<Type, object> viewModels = new Dictionary<Type, object>();
private T CreateViewModel<T>() where T:new()
{
var type = typeof (T);
object existing;
if (!viewModels.TryGetValue(type, out existing))
{
existing = new T();
viewModels[type] = existing;
}
return (T)existing;
}
And there you have it – view model location across all applications.
What if my wife will try to fill and save two items edited using same instance of ViewModel but two popup windows???