Mvvm 如何使用PRISM和MEF将视图注入UI?

Mvvm 如何使用PRISM和MEF将视图注入UI?,mvvm,prism,mef,Mvvm,Prism,Mef,我已经搜索了一些教程,甚至还查看了PRISM的pluralsite简介。但是,大多数示例都是基于使用unity容器和Mef容器来实现此功能的,缺乏相关信息。 我的简单helloworld模块基于。我的代码是相同的,只是我只停留在HelloModule上,使用Mef,而不是Unity,如教程所示: 主要问题是如何使用视图模型初始化视图。我通过实验找到的唯一有效方法是在视图构造函数中初始化视图模型: HelloView.xaml.cs namespace Hello.View { [Expo

我已经搜索了一些教程,甚至还查看了PRISM的pluralsite简介。但是,大多数示例都是基于使用unity容器和Mef容器来实现此功能的,缺乏相关信息。 我的简单helloworld模块基于。我的代码是相同的,只是我只停留在HelloModule上,使用Mef,而不是Unity,如教程所示:


主要问题是如何使用视图模型初始化视图。我通过实验找到的唯一有效方法是在视图构造函数中初始化视图模型:

HelloView.xaml.cs
namespace Hello.View
{
    [Export]
    public partial class HelloView : UserControl, IHelloView
    {
        public HelloView()
        {
            InitializeComponent();
            Model = new HelloViewModel(this);
        }

        public IHelloViewModel Model
        {
            //get { return DataContext as IHelloViewModel; }
            get { return (IHelloViewModel)DataContext; }
            set { DataContext = value; }
        }
    }
}
和标准模块初始化代码:

[ModuleExport(typeof(HelloModule), InitializationMode=InitializationMode.WhenAvailable)]
    public class HelloModule : IModule
    {
        IRegionManager _regionManager;

        [ImportingConstructor]
        public HelloModule(IRegionManager regionManager)
        {
            _regionManager = regionManager;
        }

        public void Initialize()
        {
            _regionManager.Regions[RegionNames.ContentRegion].Add(ServiceLocator.Current.GetInstance<HelloView>());
        }
    }
[ModuleExport(typeof(HelloModule),InitializationMode=InitializationMode.whenavaailable)]
公共类HelloModule:IModule
{
IRegionManager(区域管理员);
[导入构造函数]
公共HelloModule(IRegionManager区域管理器)
{
_regionManager=regionManager;
}
公共无效初始化()
{
_regionManager.Regions[RegionNames.ContentRegion].Add(ServiceLocator.Current.GetInstance());
}
}

但是,如果有人能告诉我正确的方法,我认为这必须在模块初始化部分完成。

您实现
HelloView
的方式意味着
视图必须知道
IHelloViewModel
的确切实现,这在某些情况下很好,但这意味着您不需要这个
接口

对于我提供的示例,我正在使用
属性注入
,但是
构造函数注入
也可以

如果要使用
接口
,可以这样实现:

[导出(类型化(IHelloView)]
公共部分类HelloView:UserControl,IHelloView
{
公共HelloView()
{
初始化组件();
}
[进口]
公共IHelloViewModel模型
{
获取{返回DataContext作为IHelloViewModel;}
设置{DataContext=value;}
}
}
[导出(类型(IHelloViewModel))]
公共类HelloViewModel:IHelloViewModel
{
}
否则它会像这样:

[导出(类型化(IHelloView)]
公共部分类HelloView:UserControl,IHelloView
{
公共HelloView()
{
初始化组件();
}
[进口]
公共HelloViewModel模型
{
获取{返回DataContext作为HelloViewModel;}
设置{DataContext=value;}
}
}
[出口]
公共类HelloViewModel
{
}

还有一件事:如果您不想更改
视图或提供它们的多个实现,您不需要为它们提供
接口。

MatthiasG展示了在MEF中定义模块的方法。请注意,视图本身并没有实现IModule。然而,将MEF与PRISM一起使用的有趣部分是如何导入在启动时将模块导入UI

在这里,我只能从原则上解释该系统,但它可能会为您指出正确的方向。任何事情都有多种方法,但这是我所理解的最佳实践,也是我在以下方面取得的非常好的经验:

自举

与Prism和Unity一样,它都是从引导程序开始的,它源自Microsoft.Practices.Prism.MefExtensions中的
MefBootTrapper
。引导程序设置MEF容器,从而导入所有类型,包括服务、视图、视图模型和模型

导出视图(模块)

这是MatthiasG所指的部分。我的实践是GUI模块的以下结构:

  • 模型使用
    [Export(typeof(MyModel)]
    属性将自身导出为其具体类型(也可以是一个接口,请参见MatthiasG)。使用
    [PartCreationPolicy(CreationPolicy.Shared)]
    标记以指示只创建了一个实例(单例行为)

  • ViewModel会像模型一样将自身导出为其具体类型,并通过构造函数注入导入模型:

    [导入构造函数] 公共类MyViewModel(MyModel模型) { _模型=模型; }

  • 视图通过构造函数注入导入ViewModel,与ViewModel导入模型的方式相同

  • 现在,这一点很重要:视图使用特定属性导出自身,该属性派生自“标准”
    [Export]
    属性。以下是一个示例:

[ViewExport(RegionName=RegionNames.DataStorageRegion]
公共部分类DataStorageView
{
[导入构造函数]
公共数据存储视图(数据存储视图模型视图模型)
{
初始化组件();
DataContext=viewModel;
}
}
查看导出]属性

[ViewExport]
属性做两件事:因为它派生自
[Export]
属性,它告诉MEF容器导入视图。作为什么?这隐藏在它的定义中:构造函数签名如下所示:

public ViewExportAttribute():base(typeof(UserControl)){
通过调用类型为
UserControl
[Export]
的构造函数,每个视图都会在MEF容器中注册为
UserControl

其次,它定义了一个属性
RegionName
,该属性稍后将用于决定在Shell UI的哪个区域插入视图。RegionName属性是接口
IViewRegionRegistration
的唯一成员。属性类:

//
///标记UserControl以将其导出到具有指定名称的区域
/// 
[导出(类型(IViewRegion注册))]
[AttributeUsage(AttributeTargets.Class,AllowMultiple=false)]
[元数据属性]
公共密封类ViewExportAttribute:ExportAttribute,IViewRegion注册
{
public ViewExportAttribute():基(typeof(U)