[MVVMbasics] Avoiding duplicate Viewmodel instances in Windows Store Apps

All blog posts with a title that starts with [MVVMbasics] are related to the MVVMbasics framework. If you are only interested in my regular blog posts and not in MVVMbasics, ignore these. To list all articles covering MVVMbasics, go to http://mvvmbasics.mobilemotion.eu/documentation!

In any MVVM application, it is necessary to link the Viewmodel to the View. In .NET/XAML, this is usually done by setting the View’s DataContext property to a new instance of the Viewmodel:

<PhoneApplicationPage.DataContext>
	<viewmodels:MyViewmodel />
</PhoneApplicationPage.DataContext>

When using MVVMbasics and the NavigatorService for easier navigation, it is not sufficient that the View knows about which Viewmodel instance to obtain the binding properties and commands from – in this case also the NavigatorService needs to know about the coupling between View and Viewmodel, in order to enable navigation to specific Viewmodels. Therefore the NavigatorService handles the binding of Viewmodels to Views internally, and it is not necessary to set DataContext manually.

The problem is: When using ReSharper, you are provided with extended Intellisense proposals, which for example allows automatic insertion of properties and commands within DataBinding markup extension tags – but this works only if you’ve specified the View’s DataContext at compile-time (from within XAML code).

In most cases, assigning the same Viewmodel class to a View twice (once by setting the DataContext property in XAML, once through MVVMbasics) does not lead to functional problems during application lifetime, but it allocates more memory than necessary (because actually two instances of the same Viewmodel class are created, one of which is not needed at runtime). Moreover, when using MVVMbasics 1.2 (or a newer version) in Windows Store Apps, this pattern has more severe drawbacks: In this case, whenever closing a page and returning back to the previously active page, this page’s Viewmodel instance is overwritten, including all its properties – which means that it is not possible to store data within a Viewmodel while navigating through the application! To avoid this, you should definitely leave the whole Viewmodel coupling task to the MVVMbasics framework and simply not set the DataContext property in your XAML pages.

Okay, but you’ll still want to benefit from ReSharper’s code fragment proposals, right? How can you accomplish this without setting a View’s DataContext at compile-time?

Simply use XAML design-time properties: First, make sure that the following namespace declarations are included in the page’s header:

xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

In addition, the mc:Ignorable="d" attribute must be set for the page. Now, it is possible to add the d:DataContext attribute to the page. But how to specify a new instance of some Viewmodel class as content of this attribute? Here another component from the d namespace comes into play: d:DesignInstance allows to create an instance of some class, pass it to the containing object – and make sure that this happens only at design-time, not when the application is actually running!

Here comes an example of the full page that can replace the code fragment presented at the beginning of this article:

<views:BaseView
    x:Class="MyPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MVVMbasicsTestTablet"
    xmlns:views="using:MVVMbasicsTabletExtensions.Views"
	xmlns:viewmodels="using:MyApp.Viewmodels"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
	d:DataContext="{d:DesignInstance viewmodels:MyViewmodel}">

	<!-- insert page content here-->
	
</views:BaseView>

The best is: This works for all three platforms (Windows Store, Windows Phone, and WPF Desktop), and I’d strongly recommend to use this pattern on all platforms you’re developing for, since it helps to avoid both functional and performance-related issues, as stated above!