2013-03-08 28 views
6

我已经搜索了一些教程,甚至看着pluralsite介绍PRISM。但是,大多数基于使用统一容器的示例以及缺少有关如何使用Mef容器实现此功能的信息。 我简单的HelloWorld模块是基于web tutorial。我的代码是相同的,除了我坚持只HelloModule和使用MEF,没有统一的教程我显示:Views如何使用PRISM和MEF注入到UI中?

主要我的问题如何初始化我的观点与我的视图模型。我已经通过实验发现的唯一的工作方法是查看构造函数初始化视图模型:

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

然而,谁能告诉正确的路该怎么这个事情,我这必须在模块初始化部分完成。

+0

初始化视图模型视图构造函数是一个很好的方式。你有这样的问题吗? – thumbmunkeys 2013-03-08 08:02:55

+0

使用Unity,他们通过容器初始化视图模型。它使我在mef中寻找同等的方式?但是,如果你说这是好的方式,我不会狠心,谢谢。 – user2147528 2013-03-08 08:19:43

回答

1

你实现HelloView的方式意味着,View必须知道的IHelloViewModel确切的实施是在某些情况下罚款,但同时也意味着你不会需要这个interface

对于我提供的示例,我使用的是property injection,但constructor injection也可以。

如果你想使用interface你可以这样实现它:

[Export(typeof(IHelloView)] 
public partial class HelloView : UserControl, IHelloView 
{ 
    public HelloView() 
    { 
     InitializeComponent(); 
    } 

    [Import] 
    public IHelloViewModel Model 
    { 
     get { return DataContext as IHelloViewModel; } 
     set { DataContext = value; } 
    } 
} 

[Export(typeof(IHelloViewModel))] 
public class HelloViewModel : IHelloViewModel 
{ 
} 

否则,它应该是这样的:

[Export(typeof(IHelloView)] 
public partial class HelloView : UserControl, IHelloView 
{ 
    public HelloView() 
    { 
     InitializeComponent(); 
    } 

    [Import] 
    public HelloViewModel Model 
    { 
     get { return DataContext as HelloViewModel; } 
     set { DataContext = value; } 
    } 
} 

[Export] 
public class HelloViewModel 
{ 
} 

一两件事:如果你不想改变你的Views或为他们提供的几种实现,你不需要为他们interface

11

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

+0

嗨,马克,写得很好。我只是试图开始使用MEF和PRISM,说实话我完全失去了。我找不到任何好的基本教程,这些教程能够引导你完成所有这些,MSDN的教程只涵盖零散的部分,而示例项目对于我来说太复杂了,而不知道我在看什么。你知道任何关于MEF和PRISM的好教程,你可以指点我吗? – NZJames 2013-10-21 15:14:04

+0

@ user1122909对她很好,你喜欢它。你有没有看过Mike Taulty的Screencast(链接在我的文章中)?花几个小时,你会学到很多东西。我基本上通过这些视频了解了PRISM/MEF,没有其他。 PRISM手册也可以查找,但我不会有太高的期望在这里... – Marc 2013-10-22 06:38:18

+0

不会现在看看,非常感谢。就在同时,我不认为你对我发布的问题有任何想法:MEF/Prism? http://stackoverflow.com/questions/19526287/wpf-mef-prism-initial-region-loading – NZJames 2013-10-23 08:52:49