MVVM

Using ViewModelLocator and UnityContainer to resolve runtime and design time ViewModel instance

We can use a ViewModel locator class to resolve runtime and design time data. Again, we need to identify if it’s in design mode or not, if it’s in design mode, we add the mock extension if not, we add the actual extension.

public class ViewModelLocator
{
	UnityContainer Container;

	public ViewModelLocator()
	{
		this.container = new UnityContainer();

		if(this.IsInDesignMode)
			this.Container.AddNewExtension<MockContainerExtension>();
		else
			this.Container.AddNewExtension<MyAppContainerExtension>();
	}

	public MainPageViewModel Main
	{
		get
		{
			return this.Container.Resolve<MainPageViewModel>();
		}
	}
}

Now we want to create a UnityContainerExtension. We use the extension for us to be able to create a separate class that will initialize the design time instance and the runtime instance. You will notice that inside the MockContainerExtension’s Initialize method, instead of using RegisterType, I used RegisterInstance to provide a test data to the container. This test data will show up in the designer.

public class MockContainerExtension : UnityContainerExtension
{
	protected override void Initialize()
	{
		var mainPageViewModel = new MainPageViewModel();
		mainPageViewModel.Title = "This is my mainpage test data";
		this.Container.RegisterInstance<MainPageViewModel>(mainPageViewModel);
	}
}

public class MyAppContainerExtension : UnityContainerExtension
{
	protected override void Initialize()
	{
		this.Container.RegisterType<IDataService, SomeDataService>();
		this.Container.RegisterType<MainPageViewModel>();
	}
}

Here we can see how we create an instance of the ViewModelLocator class in the App.xaml.

<Application x:Class="MyApp.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:MyApp" RequestedTheme="Dark">
	<Application.Resources>
		<local:ViewModelLocator x:Key="ViewModelLocator" />
	</Application.Resources>
</Application>

To use the ViewModelLocator in our page we simply put it in the source of the binding and the binding path should be the property Main that should give us the MainPageViewModel.

<Page x:Class="MyApp.Views.MainPage" DataContext="{Binding Main, Source={StaticResource ViewModelLocator}}">
XAML

Prevent XAML designer and editor error caused by viewmodel initialization

The viewmodel’s constructor are being used by the designer to show some design time data. If the constructor has some dependencies that cannot be resolved, we can get an error in the xaml editor or designer. This is the reason why sometimes we can see the error in the designer or editor but when we run the app, there’s actually no error.

First thing to do is to identify all the dependencies within the cosntructor that needs to be resolved. If those dependencies cannot be resolved at design time, we have to put it inside the IsInDesignMode block or any other condition that checks if it’s currently in design mode.

example:

public MainPageViewModel()
{
	this.Items = dataService.GetItems();
}

In the code above, we have a dependency in dataService. When the designer called the constructor, It will not have any idea about the dataService, therefore it will give us an error in the xaml.

We can use IsInDesignMode (MvvmLight) to prevent those errors. IsInDesignMode is a property within the ViewModelBase class of MVVM Light. But we can also implement it on our own.

public MainPageViewModel()
{
	if(!IsInDesignMode)
		this.Items = dataService.GetItems();
}

But what if we want to put something in the Items to show in the designer? Just put it in the else block, those those will be your design time data and it will not show up on runtime.

public MainPageViewModel()
{
	if(!IsInDesignMode)
	{
		this.Items = dataService.GetItems();
	}
	else
	{
		this.Items = new List<ItemModel>();
		this.Items.Add(/* Add something */);
		this.Items.Add(/* Add something */);
		//...
	}
}

 

Aside from preventing error, it will also improve the xaml editor’s intellisense.