代码改变世界

[分享]一些在 WPF/Silverlight 中应用 MVVM 模式时可能会有点用途的代码

2013-01-04 19:35  Nana's Lich  阅读(396)  评论(0编辑  收藏  举报

想来这个博客也已经有很久没更新过了,新年新气象,现在就开始写新内容吧。

最初的起因 

在最近的几个月中我做的开发总是要跟 XAML 打交道,也就是 WPF 啊,Silverlight 啊,WF 啊这些。

在进行 WPF 和 Silverlight 开发的过程中常常要用 MVVM 模式,鉴于网络上关于 MVVM 的特点的文章一抓一大把,我这里就不进一步解释 MVVM 了。

可是,在 WPF 和 Silverlight 中应用 MVVM 时,是要在 View Model 的属性被改变的时候是要触发 INotifyPropertyChanged.PropertyChanged 事件的,对于 C# 来说这部分是不能用像是“{ get; set; }”这样简化的语法来实现的;

而且 PropertyChangedEventArgs 的构造函数接受的是以 System.String 类型为载体的属性名称,这也就意味着如果把属性名称硬编码在程序中,一旦日后因为什么原因要对代码进行重构、改变属性的名称,就只能手工修改写在字符串以匹配更改之后的属性名称,在这个过程中也是很容易产生失误的。

所以往往在这个过程中开发人员可能会感到迷茫——到底 MVVM 是让事情变简单了还是变得麻烦了?

解决问题的几种办法

知道了实际应用 MVVM 模式时的困难,微软推出的 Prism 框架中便定义了 NotificationObject 类型,派生自此类型的 View Model 可以通过 RaisePropertyChanged 方法来触发 PropertyChanged 事件,而 RaisePropertyChanged 方法的其中一个重载形式接受的是签名为 Func<T> 的 Lambda 表达式,也就是说如果使用这个重载,即使我们在未来修改了属性的名称,通过 Visual Studio 的重构工具也会自动把这个改动反映到对 PropertyChanged 事件的触发中,不需要我们再手工修改字符串。

这个方法很多对表达式树有了解的人大概都想得到,实际上我自己的 ASP.NET 压缩模块和 KyuuBackground 也用了类似的方法。

但是,使用表达式树的话总会有些额外的开销的,虽然对于触发事件之后的一系列连锁反应来说这个开销可能并不是什么严重问题,但仍然有人觉得代码不够整洁,所以后来在随着 Visual Studio 2012 一起到来的新版本 .NET 框架中支持了一种新的语法,通过在像是 RaisePropertyChanged 这样的方法的签名上添加 CallerMemberName 特性,就可以在调用代码中省去传递属性名称的这个细节,同时也不用担心会像使用表达式树那样产生额外的开销。

实用的机能

可惜因为种种原因,我暂时还是只能用 Visual Studio 2010,享受不到 CallerMemberName 的便利性,并且即使是可以省去手工填入属性名称的动作,对属性的后端字段的定义、访问以及对 RaisePropertyChanged 的调用还是不能省略的,代码写着写着我也烦躁了起来。

就在这个时候,我想起来 Visual Studio 中还有个功能叫做“代码段”。

有了合适的工具,事情就好办了,于是我立即动手编写代码段。

大体上,代码段看上去是这样的:

		private $type$ m$name$$end$;
		public $type$ $name$
		{
			get { return m$name$; }
			set
			{
				if (value == m$name$) return;
				m$name$ = value;
				RaisePropertyChanged(() => $name$);
			}
		}

由于后端字段和对外暴露的属性不可以重名,所以这里加了 m 字母作为前缀用以区分;同时我也经常使用 Prism 或者类似的 Library,所以是向 RaisePropertyChanged 方法中传递了一个 Lambda 表达式。

对于不使用 Prism 或者类似 Library 的开发人员,可以把对 RaisePropertyChanged 调用的这一行改为:

				RaisePropertyChanged("$name$");

而对于使用 Visual Studio 2012 的开发人员,则可以改为:

				RaisePropertyChanged();

附件中包含了完整的 .snippet 文件,可以在解压之后通过 Visual Studio 的代码段管理器导入,或者直接放入 My Code Snippets 文件夹中。

MVVM.zip