ViewModel with DataTemplates

Topics: Prism v2 - WPF 3.5
Sep 6, 2009 at 10:47 AM
Edited Sep 6, 2009 at 10:51 AM

Since i dont have a blog i thought id post my findings here.

I read this article some time ago: http://blogs.southworks.net/jdominguez/2008/05/first-approach-to-presentation-model-with-datatemplates/

A cool feature but it was unintuitive to use because DataTemplates are not rly all that good to edit in expression blend.

Soo i ended up doing my views as usercontrols and then have a ResourceDictionary for each project where i mapped each viewmodel to a view through a template.

This is pretty ugly since not i have to create an extra file.

I also have to add the datatemplate dictionary to "Application.Current.Resources.MergedDictionaries".

So i came up with the following solution, Where i register viewmodels with the corresponding view in my code with.

    // Author: Robert Nagy
    public class ViewManager : IViewManager
    {
        public void RegisterView<VM, V>()
        {
            // Not working for some reason
            //ResourceDictionary resourceDictionary = new ResourceDictionary();

            //DataTemplate dataTemplate = new DataTemplate();
            //dataTemplate.DataType = typeof(VM);
            //dataTemplate.VisualTree = new FrameworkElementFactory(typeof(V));

            //resourceDictionary.Add(typeof(VM).ToString(), dataTemplate);

            // Works
            string data = "<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"       " +
                 "  xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"                                    " +
                 "  xmlns:v=\"clr-namespace:" + typeof(V).Namespace + ";assembly=" + typeof(V).Assembly.GetName().Name + "\"          " +
                 "  xmlns:vm=\"clr-namespace:" + typeof(VM).Namespace + ";assembly=" + typeof(VM).Assembly.GetName().Name + "\">   " +
                 "  <DataTemplate DataType=\"{x:Type vm:" + typeof(VM).Name + "}\">                 " +
                 "      <v:" + typeof(V).Name + "/>                                                     " +
                 "  </DataTemplate>                                                                             " +
                 "</ResourceDictionary>                                                                         ";

            ResourceDictionary resourceDictionary = (ResourceDictionary)XamlReader.Parse(data);
            Application.Current.Resources.MergedDictionaries.Add(resourceDictionary);  
        
        }
    }

then in my bootstrapper i register it with the unitycontainer.

 this.Container.RegisterType<IViewManager, ViewManager>(new ContainerControlledLifetimeManager());

In my modules i then register my viewmodels with the corresponding view.

class MyModule
{
	public class MyModule : IModule
    {
        private readonly IUnityContainer container;
        private readonly IViewManager viewManager;

	public StartModule(IUnityContainer container, IViewManager viewManager)
	{
		this.container = container;
		this.viewManager = viewManager;
	}

	public void Initialize() 
	{ 
		this.RegisterViewsAndServices(); 
		this.regionManager.Regions["MyRegion"].Add(this.container.Resolve<IMyViewModel>(); 
	} 

	protected void RegisterViewsAndServices() 
	{ 
		this.container.RegisterType<IMyViewModel, MyViewModel>(); 
		this.viewManager.RegisterView<MyViewModel, MyView>();  // Register ViewModel-View pair.
	} 
}

And it works, as soon as i insert a viewmodel into a "region" it gets rendered with the specified view.

this.Container.RegisterType<IViewManager, ViewManager>(new ContainerControlledLifetimeManager());