Search code examples
c#mvvmprismmefdatatemplate

Using MEF, how to export a view for an ItemsControl?


enter code hereMaybe the title is not so specific.

The situation which I'm having is. I've got an ItemsControl where I insert many ViewModels, and this ItemsControl should have to show the View through DataTemplates.

So, I write these in a ResourceDictionary:

enter image description here

And then, I add this ResourceDictionary to the ApplicationResources.

This is so redundant and tiredsome.

I'm using MVVM also, so I was thinking if could be a way to use MEF to discover the corresponding the View that should draw. I was investigating that creating a custom attribute tag could be a good idea to simplify these redundant code, maybe adding this tag in the view telling it that this ViewModel should draw for this View, but I get lost with MEF.

The plan is to remove the ResourceDictionary.

Can you lend me a little hand?

Thanks in advance.


Solution

  • [System.ComponentModel.Composition.InheritedExport(typeof(ProblemView))]
    public abstract class ProblemView : UserControl // or whatever your Views inherit
    {
       public abstract Type ViewModelType { get; }
    }
    
    [System.ComponentModel.Composition.InheritedExport(typeof(ProblemViewModel))]
    public abstract class ProblemViewModel : BaseViewModel // or whatever your ViewModels inherit
    {
    }
    
    // in your App class
    {
       [ImportMany(typeof(ProblemView))]
       public ProblemView[] Views { get; set; }
       [ImportMany(typeof(ProblemViewModel))]
       public ProblemViewModel[] ViewModels { get; set; }
    
       void MarryViewViewModels()
       {// called during MEF composition
          foreach (ProblemView view in Views)
          {
             foreach(ProblemViewModel vm in ViewModels)
             {
                if(Equals(view.ViewModelType, vm.GetType())
                {// match -> inject the ViewModel
                   view.DataContext = vm;
                   break;
                }
             }      
          }
       }
    }
    
    // example of usage
    public partial class SomeView : ProblemView
    {
       public override Type ViewModelType { get { return typeof(SomeViewModel); } }
    }