WPF Step By Step 系列-Prism框架在项目中使用

回顾

上一篇,我们介绍了关于控件模板的用法,本节我们将继续说明WPF更加实用的内容,在大型的项目中如何使用Prism框架,并给予Prism框架来构建基础的应用框架,并且如何来设计项目的架构和模块,下面我们就来一步步开始吧。

本文大纲

1、Prism框架下载和说明

2、Prism项目预览及简单介绍。

3、Prism框架如何在项目中使用。

Prism框架下载和说明

Prism框架是针对WPF和Silverlight的MVVM框架,这个大家应该之前,都有所耳闻,关于该框架的具体说明,可以参考如下地址:

Prism框架下载

Prism框架通过功能模块化的思想,来讲复杂的业务功能和UI耦合性进行分离,通过模块化,来最大限度的降低耦合性,很适合我们

进行类似插件话的思想来组织系统功能。并且模块之间,通过发布和订阅事件来完成信息的通信。而且其开放性支持多种框架集成。

Prism项目预览及简单介绍

框架下载完毕后,解压后的文件的组织模式如下:

我们先打开Hello World QuickStart.bat看看

上面是项目的组织结构,关于该项目内部的代码结构和写法,我们来一一分析和解释。

A、先看看HelloworldModule的代码和内容。

Views文件夹中包含了UI视图界面内容。

其中只是包含了一个Textbox文本控件,其他没有太多的内容。

接着看看该设计文件对应的后台cs文件中的代码。

也是没有什么特别的内容。接着我们看看Module中的内容代码:

上面对于Module中的代码,我们就简单的分析完毕了,当然这个模块没有办法独立的运行,我们肯定要将模块加载到宿主或某个控制的主界面中,把它显示出来即可,下面我们就来看看Prism最关键的部分。

B、宿主或主界面。

先看看APP文件

设计视图中未指定,那么肯定是在cs文件中的某处直接或简介指定。

果然,这里采用了BootStrapper来完成Run方法,实现应用的启动,我们可以来深挖,看看该文件中都包含什么内容。

接着,我们来看看Shell中的内容:

我们在来看看shell里面有没有什么特殊的代码,打开后台cs文件

并无任何特殊的内容。所以我们可以大概的了解到了Prism的运行机制和流程,那么运行后的效果如下:

符合预期的目标,下面我们将继续深入的挖掘Prism的强大之处。

Prism框架如何在项目中使用

Prism是一个强大的Mvvm框架,下面我们将重点讲解如何在项目使用Prism提供的基础功能,完成基于MVVM的WPF项目的框架设计和开发,包括应用程序的架构。

项目的解决方案结构,项目采用Prism作为UI框架,NHiberia+Unity作为ORM和IOC框架。

下面我们就来一步步解析项目中的每个部分的细节和最终项目如何把这些细节组织起来的做一个整体结构上的说明。关于其他的分层设计结构我就不多说了,只关注Prism部分的内容。

1、关于对Prism的基础封装

为什么不直接使用Prism,我们希望开发人员的学习成本更低,所以,我们队Prism的一些方法进行了封装,更符合开发人员之前熟悉的MVVM模式。

关于封装的具体内容,我们后续会看到代码。

2、关于Infrastructure基础设施层定义

3、具体的模块定义

4、看看程序应用宿主的定义:

通过上面,我们介绍了基础的项目和具体的模块和宿主模块的定义,下面我们就来详细的分析下Prism如何加载模块的并且模块间如何通信,如何完成业务功能的完整流程:

在之前介绍HelloWorld的时候,我们有简单的介绍了Prism的基本流程是宿主会在Bootstrappter中对模块进行装载并初始化,下面我们来看看我们在我给出的例子中的具体过程。

a、Shell的定义:

与之前的区别就是在于,我们原来是手写的字符串,这里通过单独的类定义成静态的常量成员,我们能够防止名称出错的可能。同时我们也可以避免因为某处界面上 Region符号的变化,因为某处没有修改,而造成不同步,运行出错的情况的发生,更容易统一的管理。具体的基础设施层中关于RegionType的定义 如下:

接着查看Shell的后台cs代码:

 1     /// <summary>
2 /// MainWindow.xaml 的交互逻辑
3 /// </summary>
4 [Export]
5 public partial class Shell : Window
6 {
7 public Shell()
8 {
9 InitializeComponent();
10 }
11
12 /// <summary>
13 /// 设置ViewModel
14 /// </summary>
15 /// <remarks>
16 /// This set-only property is annotated with the <see cref="ImportAttribute"/> so it is injected by MEF with
17 /// the appropriate view model.
18 /// </remarks>
19 [Import]
20 [SuppressMessage("Microsoft.Design", "CA1044:PropertiesShouldNotBeWriteOnly", Justification = "Needs to be a property to be composed by MEF")]
21 ShellViewModel ViewModel
22 {
23 set
24 {
25 this.DataContext = value;
26 if (this.DataContext != null)
27 {
28 ((ShellViewModel)this.DataContext).OnStatusChanged += new Action<string>(SystemStatusManagementEventHandler);
29 }
30 }
31 }
32
33 public void SystemStatusManagementEventHandler(string parameter)
34 {
35 if (parameter.IsNullOrEmpty())
36 {
37 throw new ArgumentNullException("无法完成操作");
38 }
39
40 switch (parameter)
41 {
42 case HM_EMSTS.WorkStation.Infrastructure.MenuParams.Max:
43 this.WindowState = System.Windows.WindowState.Maximized;
44 break;
45 case HM_EMSTS.WorkStation.Infrastructure.MenuParams.Min:
46 this.WindowState = System.Windows.WindowState.Minimized;
47 break;
48 case HM_EMSTS.WorkStation.Infrastructure.MenuParams.Close:
49 if (MessageBox.Show("是否退出系统?", "退出系统?", MessageBoxButton.OKCancel, MessageBoxImage.Question) == MessageBoxResult.OK)
50 {
51 this.Close();
52 }
53 break;
54 }
55 }
56 }

上面的代码中采用了MEF中的Export特性和Import特性。 关于MEF的内容,我这里就不多介绍了,不是很了解的可以谷歌或百度下。

继续,我们查看Shell的ViewModel定义,因为上面的后台的cs代码中有订阅相关的事件。

 1    [Export(typeof(ShellViewModel))]
2 public class ShellViewModel : HM_EMSTS.WorkStation.UICommon.NotifyBaseObject
3 {
4 public Action<string> OnStatusChanged;
5
6 [ImportingConstructor]
7 public ShellViewModel(IEventAggregator eventAggregator)
8 {
9 //注册事件
10 if (eventAggregator == null)
11 {
12 throw new ArgumentNullException("eventAggregator");
13 }
14
15 eventAggregator.GetEvent<HM_EMSTS.WorkStation.Infrastructure.Events.SystemStatusManagementEvent>().Subscribe(this.SystemStatusManagementEventHandler);
16 }
17
18 public void SystemStatusManagementEventHandler(string parameter)
19 {
20 if (parameter.IsNullOrEmpty())
21 {
22 throw new ArgumentNullException("无法完成操作");
23 }
24
25 if (OnStatusChanged != null)
26 OnStatusChanged(parameter);
27 }
28 }

上面的代码,主要是为了完成对事件的订阅,并且当收到订阅的事件时,通知出去。这里特别注意,可以参考下图:

关于Event的定义我们可以看看上述Event的定义:

如果想按照,我们之前写的那样的形式来绑定和触发事件操作的话,必须这么写。

那么下面我们来看看ShellModule的定义吧,我们这里的代码如下:

我们使用了某个Module项目中的页面来替换shell中的Region。这样保证了Shell运行起来后能够正确的显示界面。

下面来看看项目中最重要的WorkStationBootstrapper的定义

前面介绍的helloWorld里面是采用的Unity容器,这里是MEF,所以要注意的部分,有所不同。这里需要制定MEF可导入导出部件所在的目录或程序集

我们知道shell后台cs的代码定义前面也说过了,有带有export标记。那么当执行上述的代码后,将会出现在MEFbootstrappter的 Container中。这里的container是CompositionContainer是MEF中定义的。

接着查看如下方法:

通过上面的几个方法,此时,我们的主程序,就完成了对Region的解析,显示出来即可。

B、模块定义:

Module主要是为了,替换Region符合和标记为具体的界面而是用的。

我们下面挑选一个页面来展示完整的定义和操作。

1、Model定义:

当我们的Model具有自动通知机制时,特别对于列表中的某个单元格的属性发生改变后,不需要刷新整个列表,这时候就会自动完成更新,WPF会自动完成。

2、IView接口定义。

因为我们这里采用MVP的设计模式,所以要求所有的View必须继承自IView接口。

我们这里都是直接定义View对应的唯一接口即可,主要是为了MEF的Export和Import时有用。

3、View的定义。

设计视图:

后台代码:

4、ViewModel的定义。

这里由于我们采用MVP模式,所有对于不同View之间的交互,我们这里放到了Presenter中,ViewModel充当的是对IView界面的完全控制抽象。

所以我们看到这里,没有任何的业务代码。但是对已IView界面所有的绑定信息,都需要定义到该类中。

5、Presenter定义。

上面讲Presenter标记了Export。主要是在Module中对Region进行映射时使用。

然后我们来看看PresenterBase的定义,一看便明白

这样在构造展示器时,我们便可以将IView和ViewModel之间的关系完成绑定。

6、Module的定义

这样我们就完成了,一个模块的功能开发,该功能模块尽量功能独立。

最终,我们通过一个主界面,将这样功能模块组装起来即可。

最终

将上面构建的模块运行下,看看效果,也许效果不是很好看,没有设置样式。

程序运行的框架还是非常的清晰,上面是工具栏,菜单栏,内容区。通过Prism我们可以讲菜单栏或者工具栏中的功能都设计成独立的模块,分别进行装载和控制,这样能够具有非常好的扩展性和可维护性。

由于本人水平有限,还存在对Prism框架不理解或理解不深刻的地方,错误之处在所难免,还请大家批评指出,谢谢!

WPF Step By Step 系列-Prism框架在项目中使用的更多相关文章

  1. Prism框架在项目中使用

    本文大纲 1.Prism框架下载和说明 2.Prism项目预览及简单介绍. 3.Prism框架如何在项目中使用. Prism框架下载和说明 Prism框架是针对WPF和Silverlight的MVVM ...

  2. Spring Data JPA系列3:JPA项目中核心场景与进阶用法介绍

    大家好,又见面了. 到这里呢,已经是本SpringData JPA系列文档的第三篇了,先来回顾下前面两篇: 在第1篇<Spring Data JPA系列1:JDBC.ORM.JPA.Spring ...

  3. ORM Nhibernate框架在项目中的配置

    在项目中使用 Nhibernet 时,一定要将 配置文件 .xml  编译方式设置为 嵌入式资源,否则在运行项目时就会出现错误. 以下是hibernate.cfg.xml 的配置,在配置中使用的是 M ...

  4. springMVC框架在项目中的搭建

    第一步:构建Web项目    第二步:导入所需jar包    第三步:配置前端控制器DispatcherServlet    第四步:编写Controller控制器(也称为Handler处理器)   ...

  5. SWTBOK測试实践系列(5) -- 项目中使用手动和自己主动化的策略

    手动測试和自己主动化測试永远是一个非常热门的话题.自己主动化也一直被人们捧上神坛.自己主动化測试和手动測试从技术上来说本质事实上都是測试用例设计.仅仅只是终于形式一个是人工运行,一个是代码运行罢了.这 ...

  6. 项目中使用Prism框架

    Prism框架在项目中使用   回顾 上一篇,我们介绍了关于控件模板的用法,本节我们将继续说明WPF更加实用的内容,在大型的项目中如何使用Prism框架,并给予Prism框架来构建基础的应用框架,并且 ...

  7. android 项目中使用到的网络请求框架以及怎样配置好接口URL

    我们在做项目中一定少不了网络请求,如今非常多公司的网络请求这块好多都是使用一些比較好的开源框架,我项目中使用的是volley,如今讲讲一些volley主要的使用,假设想要具体的了解就要去看它的源代码了 ...

  8. WPF Step By Step 系列 - 开篇 ·

    WPF Step By Step 系列 - 开篇 公司最近要去我去整理出一个完整的WPF培训的教程,我刚好将自己学习WPF的过程和经验总结整理成笔记的方式来讲述,这里就不按照书上面的东西来说了,书本上 ...

  9. enode框架step by step之框架的物理部署思路

    enode框架step by step之框架的物理部署思路   enode框架系列step by step文章系列索引: enode框架step by step之开篇 enode框架step by s ...

随机推荐

  1. oracle第一章

    1.oracle对比sqlserver oracle sqlserver 数据文件.dbf 数据文件.mdf 控制文件.ctl   日志文件.log 日志文件.log     2.内置用户 1.sys ...

  2. SAP采购申请审批记录增强

    业务需要,开发就搞.... EBAN中增强结构:CI_EBANDB ANAME 类型 UNAME 用户名 ADATE 类型 AEDAT DATS 更改日期 ATIME 类型 UZEIT TIMS 时间 ...

  3. How to decide on the correct number of clusters?

    Determining the number of clusters/segments in hierarchical clustering/segmentation algorithms 由于uni ...

  4. DIV使用tabindex获得事件详解 移动div

    添加 tabindex='-1' 属性: 默认:获取不到焦点事件(blur) 1 <div class="wl-product" id="wl-product&qu ...

  5. easyui 中重复加载两次url

    之前一直在使用easyui中,忽视了官网上的小细节,类似于datagrid.combobox 等组件在使用的时候,它的数据加载方式分为两种: 官网中: ①在html中,比如: <table id ...

  6. 启动项目报错Error: listen EADDRINUSE

    我在使用elasticsearch的kibana插件时候,有一次启动,遇到这个错误: Error: listen EADDRINUSE 它的意思是,端口5601被其他进程占用. 故而,需要kill掉那 ...

  7. subString用法,字符串保持一定位数,不足补0

    Substrinig(a,b): 从下标a开始截取,共截取b位 实现:一串数字,中间两位数字+2,生成新的一串数字 "; , number.Length - );//前8位 );//后6位 ...

  8. MongoDB常用操作一查询find方法db.collection_name.find()

    来:http://blog.csdn.net/wangli61289/article/details/40623097 https://docs.mongodb.org/manual/referenc ...

  9. iis7.5 设置伪静态

    1)首先新建一个应用程序池,名称任意,比如:nettest,托管管道模式先暂时设置为集成模式,等下面的一系列设置完成之后再设置成经典模式: 2)部署好站点,并将此站点的应用程序池设置为nettest; ...

  10. Android TextView多行垂直滚动

    在Android应用中,有时候需要TextView可以垂直滚动,今天我就介绍一下怎么实现的.在布局里: <TextView android:id="@+id/tvCWJ" a ...