WPFStepByStep系列-Prism框架在项⽬中使⽤
回顾
上⼀篇,我们介绍了关于控件模板的⽤法,本节我们将继续说明WPF更加实⽤的内容,在⼤型的项⽬中如何使⽤Prism框架,并给予Prism 框架来构建基础的应⽤框架,并且如何来设计项⽬的架构和模块,下⾯我们就来⼀步步开始吧。
本⽂⼤纲
1、Prism框架下载和说明
2、Prism项⽬预览及简单介绍。
3、Prism框架如何在项⽬中使⽤。
Prism框架下载和说明
Prism框架是针对WPF和Silverlight的MVVM框架,这个⼤家应该之前,都有所⽿闻,关于该框架的具体说明,可以参考如下地址:
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]
5public partial class Shell : Window
6 {
7public 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 {
23set
24 {
25this.DataContext = value;
26if (this.DataContext != null)
27 {
28 ((ShellViewModel)this.DataContext).OnStatusChanged += new Action<string>(SystemStatusManagementEventHandler);
29 }
30 }
31 }
32
33public void SystemStatusManagementEventHandler(string parameter)
34 {
35if (parameter.IsNullOrEmpty())
36 {
37throw new ArgumentNullException("⽆法完成操作");
38 }
39
40switch (parameter)
41 {
42case HM_EMSTS.WorkStation.Infrastructure.MenuParams.Max:
43this.WindowState = System.Windows.WindowState.Maximized;
44break;
45case HM_EMSTS.WorkStation.Infrastructure.MenuParams.Min:
46this.WindowState = System.Windows.WindowState.Minimized;
47break;
48case HM_EMSTS.WorkStation.Infrastructure.MenuParams.Close:
49if (MessageBox.Show("是否退出系统?", "退出系统?", MessageBoxButton.OKCancel, MessageBoxImage.Question) == MessageBoxResult.OK)
50 {
51this.Close();
52 }
53break;
54 }
55 }
56 }
上⾯的代码中采⽤了MEF中的Export特性和Import特性。关于MEF的内容,我这⾥就不多介绍了,不是很了解的可以⾕歌或百度下。
继续,我们查看Shell的ViewModel定义,因为上⾯的后台的cs代码中有订阅相关的事件。
1 [Export(typeof(ShellViewModel))]
2public class ShellViewModel : HM_EMSTS.WorkStation.UICommon.NotifyBaseObject
3 {
4public Action<string> OnStatusChanged;
5
6 [ImportingConstructor]
7public ShellViewModel(IEventAggregator eventAggregator)
8 {
9//注册事件
10if (eventAggregator == null)
11 {
12throw new ArgumentNullException("eventAggregator");
13 }
14
15 eventAggregator.GetEvent<HM_EMSTS.WorkStation.Infrastructure.Events.SystemStatusManagementEvent>().Subscribe(this.SystemStatusManagementEventHandler);
16 }
17
18public void SystemStatusManagementEventHandler(string parameter)
19 {
20if (parameter.IsNullOrEmpty())
21 {
22throw new ArgumentNullException("⽆法完成操作");
23 }
24
25if (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的解析,显⽰出来即可。bootstrap项目
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框架不理解或理解不深刻的地⽅,错误之处在所难免,还请⼤家批评指出,谢谢!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论