`

初学Prism、MEF应用陷阱例一

 
阅读更多

转自 http://www.189works.com/article-42722-1.html

 

最近熟悉了一下Prism框架,将自己理解的主要知识点分为如下:

1、BootStrapper-启动引导

2、Region-区域

3、Module-模块

4、Aggregate-聚合事件

5、MVVM

 

根据Prism的QuikStart 以及网上诸多的示例,应用,我们很快便能理解其中的一些知识,并且非常跃跃欲试!

 

经过一翻学习、运行示例之后…………… 开始了自己的第一个Prism应用;

 

按照学习到的知识:

首先、我们新建项目、创建一个Shell 并且标记[Export]

 [Export]    public partial class Shell : Window

 

接着、添加BootStrapper类,重写CreateShell()以及InitializeShell方法

 public class BootStrapper : MefBootstrapper
    {
        protected override DependencyObject CreateShell()
        {
            //注意:Prism的Mef.Container.Catalog的配置来自AggregateCatalog
            return this.Container.GetExportedValue<Shell>();
        }
 protected override void InitializeShell()
        {
            base.InitializeShell();
 
            Application.Current.MainWindow = (Shell)this.Shell;
            Application.Current.MainWindow.Show();
        }
}

 

最后、修改App文件通过BootStrapper.Run()来启动应用

public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
 
            new BootStrapper()
                .Run();
        }
    }

 

121、三步走就完成了,原来这么简单哦!!

 

满怀欣喜的您如果真的这样做了,并且运行、你就会跟我一样杯具的发现在

return this.Container.GetExportedValue<Shell>();

这里报错哦~~~ oh my god! 所报错误为MEF无法匹配Export元数据!

 

 

为什吗,为什吗呢? 猴急的你也许会跟我一样,重新打开官方示例仔细查看,甚至是copy code过来,也许你还会像我一样往官方示例添加NewShell 试试,或者新建项目添加Shell 并使用官方项目来getExport它!!!!

 

但是猴急一圈下来,有可能您发现还是错的,如果您运气好,完全copy了官方示例来测试没有出错,那也只能说你不会理解到本文下面将要降到的陷阱!

 

Technorati 标签: 在这里先插播一条信息:我们发现官方示例中一些重写方法对base.的调用都写在重写代码之前,这让有点代码洁癖的我们看着就有点不顺眼了,因为我们通常喜欢把base.放在自实现之后!为什么Prism的示例要这样做呢,原因下面再说!

 

到这里之后,说实话,我怀疑过我的系统环境,怀疑我新建的项目问题,怀疑过.g.cs的隐藏文件,我甚至拿文本打开项目文件去对比到底有啥差异!

唯一没做的就是去查看prism源码,在google了一翻、苦思冥想了一翻,群里扯了一翻之后,问题还是没有解决的情况下,我开始打开prism的源码一探究竟!

(如果您也经过了这些磨难,甚至认为Prism太操蛋的时候,那赶紧继续往下看吧)

 

我们需要查看的就是MefBootstrapper类,作为一个菜鸟 ,我们一定要准确快速的定位问题:直接飞至MefBootstrapper类Run方法

this.Logger.Log(Resources.CreatingMefContainer, Category.Debug, Priority.Low);
            this.Container = this.CreateContainer(); //方法内部Catalog来自AggregateCatalog
            if (this.Container == null)
            {
                throw new InvalidOperationException(Resources.NullCompositionContainerException);
            }
 
            this.Logger.Log(Resources.ConfiguringMefContainer, Category.Debug, Priority.Low);
            this.ConfigureContainer();  //内部调用RegisterBootstrapperProvidedTypes注册下列Export
            /*
            this.Container.ComposeExportedValue<ILoggerFacade>(this.Logger);
            this.Container.ComposeExportedValue<IModuleCatalog>(this.ModuleCatalog);
            this.Container.ComposeExportedValue<IServiceLocator>(new MefServiceLocatorAdapter(this.Container));
            this.Container.ComposeExportedValue<AggregateCatalog>(this.AggregateCatalog);
             */

 

看看我们重写的方法实实在在的在Run方法里做了一些初始化了,

抓住

this.Container = this.CreateContainer(); //方法内部Catalog来自AggregateCatalog
 protected virtual CompositionContainer CreateContainer()
        {
            CompositionContainer container = new CompositionContainer(this.AggregateCatalog);
            return container;
        }

看一下,结果见注释!(//方法内部Catalog来自AggregateCatalog)

 

 

这一看,如果您使用过MEF或者对MEF有所了解的话,就能很快想到问题原因了,从一开始我们的报错信息来看,是Export没有匹配到,那就是说MEF.Container中没有包含我们Export出去的东西

 

为什么没有包含,一:MEF的Catalog有问题;二:Export标记没写(#这废话),看到这里我们就知道了真是Catalog的问题,因为Prism默认的Container首先会从AggregateCatalog添加

 

那就需要继续往下看看AggregateCatalog到底干了些神马:

老老实实Create

 protected virtual AggregateCatalog CreateAggregateCatalog()
        {
            return new AggregateCatalog();
        }

 

老老实实Config

 protected virtual void ConfigureAggregateCatalog()        {        }

 

 

这就奇怪了,既然与AggregateCatalog直接相关的部分没问题,那就要继续往下看:

 protected virtual void ConfigureContainer()        {            this.RegisterBootstrapperProvidedTypes();        }

Hi,有东东哦,go go go继续跟进;

 

  protected virtual void RegisterBootstrapperProvidedTypes()
        {
            this.Container.ComposeExportedValue<ILoggerFacade>(this.Logger);
            this.Container.ComposeExportedValue<IModuleCatalog>(this.ModuleCatalog);
            this.Container.ComposeExportedValue<IServiceLocator>(new MefServiceLocatorAdapter(this.Container));
            this.Container.ComposeExportedValue<AggregateCatalog>(this.AggregateCatalog);
        }

Okay,至此我们的跟踪已经完成。同时我们也学习到了Prism博大精神的依赖注入功能;

 

闲话一句,我们发现Prism框架有个依赖组件ServiceLocator ,这是一个非常好的设计哦,建议还不了解同学都去codeplex上看下其源码,和几个扩展实现!

 

再Okay下,通过上面的简单跟踪知道了Container的Catalog内容之后,我们的问题也清楚了,那就是因为我们Export的程序集未被加载到Container的Catalog中;

 

在MEF中,Export出的东西叫做部件,存放部件的地方叫做Catalog ,这个Catalog可以是目录,程序集,也可以是代码; 当然MEF的知识还需要单独去了解哦!

 

同时这里也可以联想到为什么官方示例能够正常运行, 因为大部分示例官方非官方的 他们对Prism框架的演示都包含了Module\Region\Aggregate的应用,

 

自然他们也就在BootStrapper对Module和Aggregate进行了配置,配置的同时将包含Export的所有程序集都添加到Container中了,

 

所以在Container获取部件的时候就没有出错,这样想来的话,如果大家一步一步一个功能一个功能实现去学习的话就会遇到陷阱了!

 

Technorati 标签: 其实我也想不明白为什吗Prism的开发团队会不在基类中默认添加自身程序集的Catalog呢,也许有些应用并不需要Aggregate这类东西,那就让初学者掉入陷阱!

 

好了, 问题分析清楚了,解决办法就是将自身程序集Catalog注册到Container中去就可以了,

示例:

protected override void ConfigureAggregateCatalog()
        {
            base.ConfigureAggregateCatalog();
 
            //加载自身
            this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(this.GetType().Assembly));
 
            //加载ViewModel所在Assembly
            this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(ShellViewModel).Assembly));
 
            //加载Modules目录
            if (Directory.Exists("./Modules"))
            {
                this.AggregateCatalog.Catalogs.Add(new DirectoryCatalog("./Modules"));
            }
        }

 

 

先分享下自己的应用选型, 选择Prism框架的Module\Region\Aggregate功能,当然包含了MEF; 选择SimapleMVVM的MVVM功能;

然后是后话,Prism非常不错的框架,我们现在不管高手、菜鸟 开发的时候都在应用好的设计模式,好的开发方法 和 好的架构;

但是技术更新迅速的同时我们大都是草草了解其使用并直接应用,有时候可能没有完全理解其精粹;拿prism来说,作为企业开发框架,主打功能就是解耦、解耦的方法就是依赖注入,再一个就是设计模式;

 

我们使用prism的完全可以将项目拆分为很多小的工作模块去开发, 目前我的项目中就这样,UI就是纯UI ViewModel单独项目且Export 并且将程序集添加到Prism的Container供UI层去Import

然后ViewModel在通过 IService从Core模块中获取服务,

然后利用ServiceLocator 或者 prism 在任意地方去Import 就可以做很多工作了, 之前做WPF都是将ViewModel在View.xaml中去绑定或者写到资源里,

 

现在我更喜欢这样:

  [Import]
        public ShellViewModel ViewModel
        {
            get
            {
                return (ShellViewModel)this.DataContext;
            }
            set
            {
                this.DataContext = value;
            }
        }

 

 

结尾:对Prism的学习和应用才刚开始,有新的理解和问题我会继续和大家分享 ;另外我现在的项目为C/S分布式应用,服务端EF+WCF+WindowsService, 客户端WPF+WCF ,设计过程和解决问题的过程中也有很多有意思的东西,有时间的话我也会分享出来,供朋友们学习交流!

分享到:
评论

相关推荐

    WPF prism MEF 架构

    Prism4MefDemo是一个使用Prism和MEF实现的示例项目,它展示了如何在WPF应用中集成这两个库。项目可能包含以下组成部分: - 主应用程序(Shell):包含主窗口和导航结构,通过MEF加载并管理模块。 - 模块(Module)...

    wpf prism mef简单实例

    MEF(Managed Extensibility Framework)是.NET Framework的一个库,用于实现插件式架构,允许应用程序动态发现和使用外部组件。 **Prism与MEF的结合** 在本实例中,Prism与MEF结合使用,实现了模块化的功能。MEF...

    Prism4使用MEF的演示项目

    Prism(普林斯)是一个开源的、可重用的软件开发框架,用于构建具有模块化、松散耦合和可测试性的 WPF 和 Silverlight 应用程序。Prism 4 是其一个版本,它主要为微软的 .NET 平台提供了设计模式、最佳实践和组件库...

    Prism框架实例、MEF框架实例

    本解决方案中包含3个程序,1、简单的LocalDB数据的连接,项目名称是LocalDBOperate;2、Prism框架的简单实例,项目名称是Desktop.MainWindow;3、MEF的简单实例,项目名称MEFTest

    prism + mef

    1. **初始化容器**:首先,应用会创建一个MEF容器,这是整个插件架构的基础。容器负责管理和实例化组件。 2. **定义接口和导出**:每个模块通常会定义一组接口,然后实现这些接口。通过使用`[Export]`属性标记类,...

    Prism经典案例,Prism经典应用

    1. **模块化(Modularity)**:Prism的核心特性之一是模块化,它允许将大型应用程序分解为小的、独立的模块,每个模块都有自己的功能。这样可以提高代码的可重用性,使得开发和维护变得更加容易。在示例中,你可能会...

    silverlight 一个好的架构 MEF prism

    Silverlight,MEF(Managed Extensibility Framework)和PRISM(Composite Application Guidance)是微软开发技术中的重要组件,尤其在构建富互联网应用程序(RIA)时。让我们深入探讨这些概念及其在构建优秀架构中...

    Prism MVVM应用 登陆后切换主窗体实现

    应用场景  使用Prism7开发WPF程序,编码采用MVVM形式。当程序启动时,首先进入一个登陆界面,进行登陆认证,认证成功后转入程序布局主窗口。 设计思路  WPF程序框架搭建后,程序中存一个Shell.xaml,相当于表演者...

    prism+mahapp应用基础

    1. **模块化(Module)**:模块化是Prism的一个重要概念,它允许将大型应用程序分解成多个独立的、可重用的模块,每个模块都有自己的业务逻辑和视图。模块化有助于降低复杂性,便于维护和扩展。 2. **依赖注入...

    Silverlight 应用 Prism 的示例

    而Prism则是微软企业库的一个组件,它提供了一套设计模式、最佳实践和可重用组件,帮助开发者构建可维护、可扩展的WPF和Silverlight应用。在本示例中,我们将深入探讨如何在Silverlight项目中整合Prism框架,以实现...

    Prism5 For Wpf 官方帮助文档以及示例代码

    Prism是微软 Patterns & Practices 团队开发的一个框架,专门用于构建Windows Presentation Foundation(WPF)应用程序。Prism 5 是其一个版本,它引入了一系列设计模式和最佳实践,以帮助开发者创建可维护、可扩展...

    WPF Prism框架应用学习.zip

    1. **模块化**:Prism中的模块化允许将应用程序拆分为独立的功能单元,每个模块可以单独开发、测试和部署。这降低了系统的复杂性,增强了可扩展性。 2. **依赖注入**:通过Unity Container,Prism实现了依赖注入,...

    wpf prism中的command应用

    而Prism框架则是微软支持的一个用于开发WPF和UWP应用的开源库,它包含了许多最佳实践和设计模式,如MVVM(Model-View-ViewModel)、Dependency Injection(依赖注入)以及EventAggregator(事件总线)等。在Prism中...

    Prism7.1.0.431_WPF_官方中文文档.pdf

    Prism是一个为.NET框架设计的框架,其目的在于帮助开发者构建松散耦合、易于维护和扩展的复合应用程序。Prism提供了设计模式实现,比如模块化开发和模型-视图-视图模型(MVVM)模式。文档中的内容详细介绍了使用...

    Prism 4.0安装包

    Prism 4.0 是一个流行且强大的框架,主要用于构建模块化、可维护性和可扩展的WPF(Windows Presentation Foundation)和Silverlight应用程序。这个安装包包含了一系列针对Desktop、Silverlight以及Windows Phone平台...

    Prism Manual.pdf Prism8框架官方手册 MD 文件转pdf

    Prism是一个流行的框架,它可以帮助开发者构建适用于.NET平台的模块化应用程序。本手册介绍的是Prism框架的官方指南,并说明了如何将Markdown文件转换成PDF格式。Prism框架主要针对WPF(Windows Presentation ...

    WPF Prism实例(多个实例包含Prism各个重要概念实例)

    1. **模块化(Modularity)**:Prism提供了一种组织大型应用为多个独立模块的方法,每个模块可以有自己的功能和依赖,便于维护和扩展。 2. **依赖注入(Dependency Injection,DI)**:通过容器如Unity或Autofac,...

    C#Prism 例子与源码

    Prism 是一个开源的微软 .NET 框架,专为构建可扩展、模块化、松耦合的 WPF 和 UWP 应用程序而设计。它由 Microsoft patterns & practices 团队开发,旨在帮助开发者遵循最佳实践和设计模式。在 C# 中使用 Prism,...

    Prism4 Demo程序

    Prism4 Demo程序是针对微软WPF(Windows Presentation Foundation)框架的一个示例应用,它展示了Prism库的用法。Prism是一个强大的开发框架,专为构建可维护、可扩展和模块化的WPF和UWP应用程序而设计。该框架由...

Global site tag (gtag.js) - Google Analytics