.NET 4.5(C#): 利用CallerMemberName特性使MVVM Light属性定义更简洁
我曾经写过一篇文章:.NET 4.5(C#):INotifyPropertyChanged执行的演变:从表达式树到调用方信息的BindableBase类型,讲述.NET 4.5中的调用者信息和WinRT工程中Visual Studio 2012利用调用者信息生成的BindableBase类型。不过当前的WinRT的MVVM Light(V4 RTM)并没有利用调用者信息来简化INotifyPropertyChanged属性的定义。
当前MVVM Light的两种RaisePropertyChanged调用方式:
protected virtual void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression, T oldValue, T newValue, bool broadcast);
protected virtual void RaisePropertyChanged<T>(string propertyName, T oldValue, T newValue, bool broadcast);
那么INotifyPropertyChanged的属性定义要么使用原始字符串定义的样式:
#region MyProperty
public const string MyPropertyPropertyName = "MyProperty";
private string _MyProperty = null;
public string MyProperty
{
get { return _MyProperty; }
set
{
if (_MyProperty == value)
return;
_MyProperty = value;
RaisePropertyChanged(MyPropertyPropertyName);
}
}
#endregion
或者使用Expression Tree:
//使用Expression Tree
#region MyProperty
private string _MyProperty = null;
public string MyProperty
{
get { return _MyProperty; }
set
{
if (_MyProperty == value)
return;
_MyProperty = value;
RaisePropertyChanged(() => _MyProperty);
}
}
#endregion
不错,但是有很大的改进方式可以让代码更简洁,借鉴BindableBase类型,我们可以自定义一个类型继承MVVM Light的ViewModelBase,并加入一个RaisePropertyChangedEx方法,来使用调用者信息,同时对数据进行判断,这样判断代码就不用写在属性声明中了,如下代码:
//+ using GalaSoft.MvvmLight;
//+ using System.Runtime.CompilerServices;
class MyViewModelBase : ViewModelBase
{
protected virtual bool RaisePropertyChangedEx<T>(ref T oldValue, T newValue, bool broadcast, [CallerMemberName] string prop = null)
{
if (!Object.Equals(oldValue, newValue))
{
oldValue = newValue;
RaisePropertyChanged(prop, oldValue, newValue, broadcast);
return true;
}
return false;
}
}
同时我还写了个Code Snippets来快速定义这种类型的属性(snippet在文章下方),快捷方式是mnp。这样继承上面的MyViewModelBase,然后使用该Code Snippet就可以快速创建简洁的INotifyPropertyChanged属性了:
class MyViewModel : MyViewModelBase
{
//使用Code Snippets快速创建更简洁的INotifyPropertyChanged属性定义
//RaisePropertyChangedEx中的false参数代表非广播
#region MyProperty
private string _MyProperty = null;
public string MyProperty
{
get { return _MyProperty; }
set { RaisePropertyChangedEx(ref _MyProperty, value, false); }
}
#endregion
}
下面完整的Code Snippet内容(抱歉今天Skydrive登不上去,直接贴代码了,不过也不是很长)
<? version="1.0" encoding="utf-8"?>
<CodeSnippets ="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
<Title>MVVM Light中INPC属性定义</Title>
<Author>Mgen</Author>
<Shortcut>mnp</Shortcut>
</Header>
<Snippet>
<Declarations>
<Literal Editable="true">
<ID>Type</ID>
<ToolTip>属性类型</ToolTip>
<Default>string</Default>
<Function>
</Function>
</Literal>
<Literal Editable="true">
<ID>Value</ID>
<ToolTip>默认值</ToolTip>
<Default>null</Default>
<Function>
</Function>
</Literal>
<Literal Editable="true">
<ID>Prop</ID>
<ToolTip>属性名称</ToolTip>
<Default>MyProperty</Default>
<Function>
</Function>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[#region $Prop$
private $Type$ _$Prop$ = $Value$;
public $Type$ $Prop$
{
get { return _$Prop$;}
set { RaisePropertyChangedEx(ref _$Prop$, value, false); }
}
#endregion
$end$]]></Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
TAG: