Yet another way to attach ViewModels to Views

Throughout the short history of the MVVM design pattern, several methods have originated for populating Views with their ViewModels.  One of the most common methods is to use one of the frameworks (PRISM, MVVM Light, Jounce, among others).  Typically, the ViewModel is registered with an IOC container and retrieved when needed.   One of the more outstanding issues is when to take the ViewModel and assign it to a View’s DataContext.  In many cases, the connection occurs in the constructor of the View with the View requesting the ViewModel from the IOC container.  In other cases, a locator is used as a static resource in the View’s Xaml, and using DataBinding a property of the locator is bound to the DataContext.  In the latter case, the locator requests the ViewModel from the IOC container.

In a recent project, I discovered (or rediscovered) another method for binding a ViewModel to a View.   Using Unity’s IOC Container, I registered both the View and the ViewModel together.  Granted this method will not work for every scenario, but in the cases where you create Views programmatically, I believe this method works perfectly.

Unity will allow you to register a type with a key which becomes important when registering different configurations of the same type.   But  more importantly, Unity supports configuration via InjectionProperties (and other methods as well).  InjectionProperties will enable Unity to resolve your Type and inject additional values into the generated class.  InjectionProperties work like this:

   1: int expectedInt = 8;
   2: container.RegisterType<MyClass>(
   3:     new InjectionProperty("IntProperty", expectedInt));

Basically, Unity will create an instance of MyClass and set the property “IntProperty” to 8, when the container resolves the type.

For a View to be registered with its ViewModel, several steps must be taken .  The steps are simple, first register the ViewModel with Unity, then register the View with an InjectionProperty, optionally adding a key if you need to register the view multiple times with different configurations.

   1: public void RegisterDialog<TView, TViewModel>(string dialogName)
   2:     where TView : IDialogView
   3:     where TViewModel : IDialogViewModel
   4: {
   5:     if (string.IsNullOrEmpty(dialogName)) throw new ArgumentNullException("dialogName");
   6:
   7:     if (!_container.IsRegistered<TViewModel>())
   8:         _container.RegisterType<TViewModel>();
   9:
  10:     _container.RegisterType<IDialogView, TView>(dialogName,
  11:         new InjectionProperty("DataContext", new ResolvedParameter<TViewModel>()));
  12: }

In the code above, I geared the method to support some dialogs, but it’s easily modified to support any type of view you’d like.  I use Unity’s ability to name the registrations so I can register multiple views of the same type but with different ViewModels.  One item to note is the use of the ResolvedParameter class.  The ResolvedParameter instructs Unity to only create the type when it is requested.  If I “newed” up a ViewModel instead, Unity would keep around an instance of the ViewModel to inject into all resolved views.

In my Bootstrapper.cs file, where you’d normally register your classes in an IOC container,, I simply make calls to this method for any dialogs I want to create in the application.

   1: RegisterDialog<DialogView DialogViewModel>(DialogNames.OkCancelDialog);
   2: RegisterDialog<DialogView, LoginDialogViewModel>(DialogNames.LoginDialog);

Here I am registering two dialogs of type DialogView with two different ViewModels and assigning them a key.  Now, it’s trivial to gain a reference to them in the application:

   1: if (!this.User.IsLoggedIn) {
   2:     IDialogView dialog = _dialogContainer.Resolve<IDialogView>(DialogNames.LoginDialog);
   3:     dialog.Show();
   4: }

That’s all there is to it.  Of course, I’ll leave the whole Dialog framework implementation up to you.

Unity is a complex framework with many features.  InjectionProperties are only one tool to enhance the configuration of your registrations.  Unity will even allow you to call a method on your object when it’s instantiated with or without parameters.

Stay Informed

Sign up for the latest blogs, events, and insights.

We deliver solutions that accelerate the value of Azure.
Ready to experience the full power of Microsoft Azure?

Atmosera is thrilled to announce that we have been named GitHub AI Partner of the Year.

X