Prism安装、MVVM基础概念及一个简单的样例

简介:

一:Prism的下载和安装

1:在http://compositewpf.codeplex.com/上下载最新的包。

下载完毕后,运行之,选择解压目录解压之。解压完毕的根目录下有chm帮助文档。

2:运行RegisterPrismBinaries.bat注册Prism组件,注册完毕才能在VS的引用中直接找到Prism组件,否则需要手动添加这些组件。

3:运行Silverlight Only - Basic MVVM QuickStart.bat可以打开一个MVVM的简单事例。

二:MVVM理解

1:现在,我们自己创建一个普通的SilverLight样例,并且将它逐步重构成为MVVM模式。

这个 普通的SL样例需求有:在界面上放置文本框用来显示Name和Button用来显示文本框中的Name的值。

前台:

image

后台:

image

SL的目录结构:

image

2:问题来了

如果我们需要让页面的值和Student实例的值保持一致,则必须要让类型继承自INotifyPropertyChanged接口,并像下面这样编码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public  class  Student : INotifyPropertyChanged
{
     string  firstName;
     public  string  FirstName
     {
         get
         {
             return  firstName;
         }
         set
         {
             firstName = value;
             Notify( "FirstName" );
         }
     }
 
     string  lastName;
     public  string  LastName
     {
         get
         {
             return  lastName;
         }
         set
         {
             lastName = value;
             Notify( "LastName" );
         }
     }
 
     public  Student( string  firstName, string  lastName)
     {
         this .firstName = firstName;
         this .lastName = lastName;
     }
 
     void  Notify( string  propName)
     {
         if  (PropertyChanged != null )
         {
             PropertyChanged( this , new  PropertyChangedEventArgs(propName));
         }
     }
 
     #region INotifyPropertyChanged Members
     public  event  PropertyChangedEventHandler PropertyChanged;
     #endregion
}

如果应用程序中存在多个这样的类型,则每个类型都要实现自己的Notify方法,这显然是不合理的。所以,无论是Prism框架,还是轻量级的Mvvm light toolkit,都实现了一个超类来包装这种需求,在Prism里该超类是NotificationObject,而Mvvm light toolkit中是ObservableObject,当然,毫无例外滴,它们都继承自INotifyPropertyChanged。

3:现在,我们参照这两个类型,来实现自己的NotificationObject,以便加深印象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public  abstract  class  NotificationObject : INotifyPropertyChanged
{
     public  event  PropertyChangedEventHandler PropertyChanged;
 
     protected  virtual  void  RaisePropertyChanged( string  propertyName)
     {
         PropertyChangedEventHandler handler = this .PropertyChanged;
         if  (handler != null )
         {
             handler( this , new  PropertyChangedEventArgs(propertyName));
         }
     }
 
     protected  void  RaisePropertyChanged( params  string [] propertyNames)
     {
         if  (propertyNames == null ) throw  new  ArgumentNullException( "propertyNames" );
 
         foreach  ( var  name in  propertyNames)
         {
             this .RaisePropertyChanged(name);
         }
     }
 
     protected  void  RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
     {
         var  propertyName = ExtractPropertyName(propertyExpression);
         this .RaisePropertyChanged(propertyName);
     }
 
     public  static  string  ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
     {
         if  (propertyExpression == null )
         {
             throw  new  ArgumentNullException( "propertyExpression" );
         }
 
         var  memberExpression = propertyExpression.Body as  MemberExpression;
         if  (memberExpression == null )
         {
             throw  new  ArgumentException( "PropertySupport_NotMemberAccessExpression_Exception" , "propertyExpression" );
         }
 
         var  property = memberExpression.Member as  PropertyInfo;
         if  (property == null )
         {
             throw  new  ArgumentException( "PropertySupport_ExpressionNotProperty_Exception" , "propertyExpression" );
         }
 
         var  getMethod = property.GetGetMethod( true );
         if  (getMethod.IsStatic)
         {
             throw  new  ArgumentException( "PropertySupport_StaticExpression_Exception" , "propertyExpression" );
         }
 
         return  memberExpression.Member.Name;
     }
}

相应的,Student类型修改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public  class  Student : NotificationObject
{
     string  firstName;
     public  string  FirstName
     {
         get
         {
             return  firstName;
         }
         set
         {
             firstName = value;
             //Notify("FirstName");
             this .RaisePropertyChanged( "FirstName" );
         }
     }
 
     string  lastName;
     public  string  LastName
     {
         get
         {
             return  lastName;
         }
         set
         {
             lastName = value;
             //Notify("LastName");
             this .RaisePropertyChanged( "LastName" );
         }
     }
 
     public  Student( string  firstName, string  lastName)
     {
         this .firstName = firstName;
         this .lastName = lastName;
     }
   
}

4:问题再次出现,经过修改后的Student类型,是什么?

是实体Model,领域Model,还是别的什么?实际上,因为没有采用任何架构模式,当前的Student类型什么也不是,揉杂了很多功能。它既要负责提供属性,也要负责控制。

在MVVM架构模式中,和MVC称谓不同的地方,就是VM(ViewModel)部分。VM负责:接受View请求并决定调用哪个模型构件去处理请求,同时它还负责将数据返回给View进行显示。也就是说,VM完成的角色可以理解为MVC中的Control。(另外需要注意的一点是,在MVC中有一个概念叫做表现模型,所谓表现模型是领域模型的一个扁平化投影,不应和MVVM中的VIEW MODEL相混淆)。

所以,我们现在要明确这些概念。首先,将Student类型的功能细分化,VM的部分,我们跟页面名称对应起来应该叫做MainViewModel。实际项目中,功能页面会相应名为StudentView.xaml,则对应的VM名便称之为StudentViewModel.cs。我们继续重构上面的代码。

三:建立MVVM的各个部分

首先,建立View文件夹,然后,将MainPage.xmal修改为StudentView.xaml后放置到该目录下。

其次,简历ViewModels文件夹,新建一个类StudentViewModel.cs,放置到该目录下。

最后,原类型Student需要继续拆分,将作为领域模型部分的功能独立出来,放置到DomainModel文件夹下。最后的结果看起来如下:

image

1:领域模型DomainModel部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public  class  Student
{
     string  firstName;
     public  string  FirstName
     {
         get
         {
             return  firstName;
         }
         set
         {
             firstName = value;
         }
     }
 
     string  lastName;
     public  string  LastName
     {
         get
         {
             return  lastName;
         }
         set
         {
             lastName = value;
         }
     }
 
     public  Student()
     {
         //模拟获取数据
         Mock();
     }
 
     public  void  Mock()
     {
         FirstName = "firstName"  + DateTime.Now.ToString();
         LastName = "lastName"  + DateTime.Now.ToString();
     }
 
}

2:视图View部分

image

3:ViewModel部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public  class  StudentViewModel : NotificationObject
{
     public  StudentViewModel()
     {
         student = new  Student();
     }
 
     Student student;
     public  Student Student
     {
         get
         {
             return  this .student;
         }
         private  set
         {
             this .student = value;
             this .RaisePropertyChanged(() => this .student);
         }
     }
}

4:若干解释

在这个简单的事例中,领域模型Student负责获取数据,而数据来源于何处不是我们关心的重点,所以,我们直接在Student中模拟了获取数据的过程,即Mock方法。

这相当于完成了一次OneWay的过程,即把后台数据推送到前台进行显示。这只能算是完成跟UI交互的一部分功能。UI交互还需要包括从UI中将数据持久化(如保存到数据库)。而UI跟后台的交互,就需要通过命令绑定的机制去实现了。

5:命令绑定

在本里中,我们演示两类命令,一类是属性类命令绑定,一类是事件类命令绑定。

首先,我们知道,VM负责UI和领域模型的联系,所以,绑定所支持的方法一定是在VM中,于是,我们在StudentViewModel中定义一个属性CanSubmit,及一个方法Submit:

1
2
3
4
5
6
7
8
9
10
11
public  bool  CanSubmit
{
     get
     {
         return  true ;
     }
}
 
public  void  Submit()
{
    student.Mock();       
1
}

注意,Submit方法中为了简单期间,使用了模拟方法。由于Mock方法中仍然可能设计到UI的变动(如随数据库的某些具体的值变动而变动),故领域模型Student可能也会需要继承NotificationObject,在本例中,Student改变为如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public  class  Student : NotificationObject
{
     string  firstName;
     public  string  FirstName
     {
         get
         {
             return  firstName;
         }
         set
         {
             firstName = value;
             this .RaisePropertyChanged( "FirstName" );
         }
     }
 
     string  lastName;
     public  string  LastName
     {
         get
         {
             return  lastName;
         }
         set
         {
             lastName = value;
             this .RaisePropertyChanged( "LastName" );
         }
     }
 
     public  Student()
     {
         //模拟获取数据
         Mock();
     }
 
     public  void  Mock()
     {
         FirstName = "firstName"  + DateTime.Now.ToString();
         LastName = "lastName"  + DateTime.Now.ToString();
     }
 
}

其次,需要改变VIEW,如下:

image

注意途中红线框起来的部分。

经过这一次的重构之后,基本满足了一个简单的MVVM模型的需要。代码下载在这里:http://files.cnblogs.com/luminji/SilverlightApplication2.rar


本文转自最课程陆敏技博客园博客,原文链接:http://www.cnblogs.com/luminji/archive/2011/05/27/2060127.html,如需转载请自行联系原作者

相关文章
|
6月前
|
人工智能 编解码
ReCamMaster:视频运镜AI革命!单镜头秒变多机位,AI重渲染颠覆创作
ReCamMaster 是由浙江大学与快手科技联合推出的视频重渲染框架,能够根据用户指定的相机轨迹重新生成视频内容,广泛应用于视频创作、后期制作、教育等领域,提升创作自由度和质量。
480 0
|
2月前
|
JSON 监控 供应链
抖音电商 API 接口:直播数据实时监控法宝!
在直播电商时代,实时掌握直播间动态是商家制胜关键。抖音电商开放平台提供API接口,助力实现直播数据秒级监控。本文详解如何构建数据监控系统,涵盖实时销量、在线人数、热卖SKU等核心指标,通过智能控场、供应链预警、投流优化等场景提升运营效率。某美妆品牌接入后GMV提升35.7%,违规拦截效率提升200%。立即接入,让流量转化为增长动能!
519 0
|
11月前
|
前端开发 JavaScript API
React开发需要了解的10个库
本文首发于微信公众号“前端徐徐”,介绍了React及其常用库。React是由Meta开发的JavaScript库,用于构建动态用户界面,广泛应用于Facebook、Instagram等知名网站。文章详细讲解了Axios、Formik、React Helmet、React-Redux、React Router DOM、Dotenv、ESLint、Storybook、Framer Motion和React Bootstrap等库的使用方法和应用场景,帮助开发者提升开发效率和代码质量。
361 4
React开发需要了解的10个库
|
9月前
|
前端开发 Linux C#
一款开源、免费、美观的 Avalonia UI 原生控件库 - Semi Avalonia
一款开源、免费、美观的 Avalonia UI 原生控件库 - Semi Avalonia
768 10
|
Linux C# Android开发
.NET Avalonia开源、免费的桌面UI库 - SukiUI
.NET Avalonia开源、免费的桌面UI库 - SukiUI
607 5
|
10月前
|
缓存 Linux 开发者
Avalonia开源控件库强力推荐-Semi.Avalonia
【11月更文挑战第3天】Semi.Avalonia 是一个基于 Avalonia 的开源控件库,提供了丰富的自定义控件和扩展功能。它支持多种样式按钮、高级输入控件和灵活的布局容器,简化了属性设置,并提供了详细的文档支持。Semi.Avalonia 还支持多种内置主题和自定义主题,具备高效的渲染机制和合理的资源管理,适用于跨平台桌面应用程序开发。
678 2
|
开发工具 Android开发 iOS开发
探索iOS与安卓应用开发的差异及未来趋势
在移动操作系统的竞争中,iOS和安卓一直是两大巨头。本文深入探讨了这两个平台在开发环境、用户体验和市场趋势方面的不同点,并预测了未来可能的发展方向。通过比较分析,旨在为开发者提供有价值的参考,帮助他们根据项目需求和目标受众选择最适合的开发平台。
182 28
|
存储 开发框架 JSON
Winform框架中多语言的处理
Winform框架中多语言的处理
|
开发框架 前端开发 JavaScript
探索现代Web开发中的框架选择:Blazor、Angular和React的全面比较与分析
【8月更文挑战第31天】随着Web开发技术的发展,选择合适的框架对项目成功至关重要。本文对比了三大前端框架:Blazor、Angular和React。Blazor是微软推出的.NET Web客户端开发框架,支持C#编写前端代码;Angular由Google支持,基于TypeScript,适用于大型应用;React是由Facebook维护的高效JavaScript库。
363 0
|
传感器 数据采集 物联网
探索未来:.NET nanoFramework引领嵌入式设备编程革新之旅
【8月更文挑战第28天】.NET nanoFramework 是一款专为资源受限的嵌入式设备设计的轻量级、高性能框架,基于 .NET Core,采用 C# 进行开发,简化了传统底层硬件操作的复杂性,极大提升了开发效率。开发者可通过 Visual Studio 或 Visual Studio Code 快速搭建环境并创建项目,利用丰富的库和驱动程序轻松实现从基础 LED 控制到网络通信等多种功能,显著降低了嵌入式开发的门槛。
242 0

热门文章

最新文章