使用MEF,如何导出ItemsControl的视图?

时间:2012-08-22 19:52:30

标签: c# mvvm prism mef datatemplate

enter code here也许标题不是那么具体。

我所拥有的情况是。我有一个ItemsControl,其中我插入了许多ViewModels,此ItemsControl必须显示ViewDataTemplates

所以,我在ResourceDictionary

中写下这些内容

enter image description here

然后,我将此ResourceDictionary添加到ApplicationResources

这太多了,太累了。

我也在使用MVVM,所以我在考虑是否可以使用MEF来发现应该绘制的相应View。我正在研究创建一个自定义属性标签可能是一个很好的想法来简化这些冗余代码,也许在视图中添加这个标签告诉它这个ViewModel应该为这个视图绘制,但我迷失了MEF。 / p>

计划是删除ResourceDictionary

你能借给我一把手吗?

提前致谢。

3 个答案:

答案 0 :(得分:2)

在我的主机WPF应用程序中,我添加了这个导入:

[ImportMany("ApplicationResources", typeof(ResourceDictionary))]
public IEnumerable<ResourceDictionary> Views { get; set; }

ResourceDictionary的代码:

[Export("ApplicationResources", typeof(ResourceDictionary))]
public partial class ItemView : ResourceDictionary 
{
    public ItemView()
    {
        InitializeComponent();
    }
}

作为参考,示例ResourceDictionary的Xaml如下所示:

<DataTemplate DataType="{x:Type local:ItemViewModel}">
    ...
</DataTemplate>

在WPF应用程序中,在主窗口之前:

// Add the imported resource dictionaries
// to the application resources
foreach (ResourceDictionary r in Views)
{
    this.Resources.MergedDictionaries.Add(r);
}

答案 1 :(得分:1)

[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); } }
}

答案 2 :(得分:0)

让我解释一下如何设置这样的东西。您可以在官方documentation

中查找更多信息

最佳实施方法是使用界面和鸭子打字。

public interface IModule {
    DataTemplate Template { get; set; }
    string Name{get;set;}
    ...
}

然后对于每个插件,继承此接口

[Export(typeof(IModule ))]
public class SampleModule : IModule {
    private DataTemplate template;
    public DataTemplate IModule.Template {
        get { return this.teplate; }
        set { this.template = value; }
    }

    private string name = "SamplePlugin";
    public string  IModule.Name{
        get { return this.name ; }
        set { this.name = value; }
    }

    ...
}

类SampleModule处于单独的程序集中,而IModule与Application和每个模块程序集都是通用的。

现在您需要加载应用程序可用的每个模块。此代码段来自应用程序窗口

...
[ImportMany]
public IEnumerable<IModule> ModulesAvailable {get;set;}
...
public void LoadModules(string path) {
    DirectoryCatalog catalog = new DirectoryCatalog(path);
    catalog.ComposeParts(this);
}

现在您可以使用foreach循环并将它们添加到Application Resource

foreach(IModule module in ModulesAvailable) {
    Application.Current.Resources.Add(module.Template, module.Name);
}

这只是概念,代码未经过测试,它写在你的答案框中,我甚至没有尝试检查语法错误的语法,这对我来说是非常的。

我在几个月前的high-school final project中找到了MEF,所以你可以查看我的代码。它是具有公式支持的电子表格应用程序,其中所有操作和操作数都作为插件加载,因此它非常灵活。