MatthiasG示出了在MEF定义模块的方式。请注意,视图本身不实现IModule。然而,在PRISM中使用MEF的有趣部分是如何在启动时将模块导入到UI中。
我只能解释原则的系统在这里,但它可能为你指明正确的方向。总是有许多方法的一切,但是这是我的理解是最好的做法,我有取得了很好的经验:
自举
与棱镜和团结,这一切都与开始Bootstrapper,源自MefBootstrapper
,在Microsoft.Practices.Prism.MefExtensions
。引导程序设置MEF容器,从而导入所有类型,包括服务,视图,视图模型和模型。
导出视图(模块)
这是MatthiasG指的部分。我的做法是,GUI模块的结构如下:
模型出口本身作为其具体类型(可以是一个接口也一样,见MatthiasG),采用[Export(typeof(MyModel)]
属性。用[PartCreationPolicy(CreationPolicy.Shared)]
标记以表示仅创建一个实例(单例行为)。
视图模型出口本身作为其具体类型就像模型和通过构造喷射进口型号:
[ImportingConstructor] 公共类MyViewModel(为MyModel模型) { _model =模型; }
的阅览通过构造函数注入进口视图模型,以同样的方式视图模型导入模型
而现在,这一点很重要:视图出口本身具有特定属性的,它是从派生'standard'[Export]
属性。这里有一个例子:
[ViewExport(RegionName = RegionNames.DataStorageRegion)]
public partial class DataStorageView
{
[ImportingConstructor]
public DataStorageView(DataStorageViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
}
}
的[ViewExport]属性
的[ViewExport]
属性做了两两件事:因为它从[Export]
属性派生,它告诉MEF容器导入视图。作为什么?这是隐藏在它的确定指标:构造函数签名如下所示:
public ViewExportAttribute() : base(typeof(UserControl)) {}
通过调用[Export]
类型的UserControl
构造,每个视图被注册为MEF容器UserControl
。
其次,它定义了一个属性RegionName
,稍后将用它来决定你的Shell UI的哪个区域应该被插入。 RegionName属性是接口IViewRegionRegistration
的唯一成员。属性类:
/// <summary>
/// Marks a UserControl for exporting it to a region with a specified name
/// </summary>
[Export(typeof(IViewRegionRegistration))]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
[MetadataAttribute]
public sealed class ViewExportAttribute : ExportAttribute, IViewRegionRegistration
{
public ViewExportAttribute() : base(typeof(UserControl)) {}
/// <summary>
/// Name of the region to export the View to
/// </summary>
public string RegionName { get; set; }
}
导入浏览
现在,该系统的最后一个关键部分是行为,你重视你的shell的地区:AutoPopulateExportedViews
行为。这样可以导入所有的模块从MEF容器与这条线:
[ImportMany]
private Lazy<UserControl, IViewRegionRegistration>[] _registeredViews;
这将导入从容器注册为UserControl
所有类型的,如果他们有一个元数据属性,它实现IViewRegionRegistration
。由于您的[ViewExport]
属性具有此功能,因此这意味着您导入标有[ViewExport(...)]
的每种类型。
的最后一步是堵塞查看到的区域,其中bahvior确实在它的OnAttach()
属性:
/// <summary>
/// A behavior to add Views to specified regions, if the View has been exported (MEF) and provides metadata
/// of the type IViewRegionRegistration.
/// </summary>
[Export(typeof(AutoPopulateExportedViewsBehavior))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class AutoPopulateExportedViewsBehavior : RegionBehavior, IPartImportsSatisfiedNotification
{
protected override void OnAttach()
{
AddRegisteredViews();
}
public void OnImportsSatisfied()
{
AddRegisteredViews();
}
/// <summary>
/// Add View to region if requirements are met
/// </summary>
private void AddRegisteredViews()
{
if (Region == null) return;
foreach (var view in _registeredViews
.Where(v => v.Metadata.RegionName == Region.Name)
.Select(v => v.Value)
.Where(v => !Region.Views.Contains(v)))
Region.Add(view);
}
[ImportMany()]
private Lazy<UserControl, IViewRegionRegistration>[] _registeredViews;
}
通知.Where(v => v.Metadata.RegionName == Region.Name)
。这将使用该属性的RegionName属性来仅获取为特定区域导出的那些视图,您将该行为附加到。
行为被附加到引导程序你的shell的地区:
protected override IRegionBehaviorFactory ConfigureDefaultRegionBehaviors()
{
ViewModelInjectionBehavior.RegionsToAttachTo.Add(RegionNames.ElementViewRegion);
var behaviorFactory = base.ConfigureDefaultRegionBehaviors();
behaviorFactory.AddIfMissing("AutoPopulateExportedViewsBehavior", typeof(AutoPopulateExportedViewsBehavior));
}
我们兜了一圈,我希望,这可以让你的事情是如何落入地方MEF的一个想法, PRISM。
而且,如果你仍然不无聊:这是完美的:
Mike Taulty's screencast
初始化视图模型视图构造函数是一个很好的方式。你有这样的问题吗? – thumbmunkeys 2013-03-08 08:02:55
使用Unity,他们通过容器初始化视图模型。它使我在mef中寻找同等的方式?但是,如果你说这是好的方式,我不会狠心,谢谢。 – user2147528 2013-03-08 08:19:43