您的位置:首页 > 其它

MvvmLight学习心得三

2013-01-05 21:16 323 查看
MvvmLight的抽象类ViewModelBase继承了ObservableObject这个类,我们来看看这个类:

/// <summary>
/// 一个基类,为了使它的对象属性必须具有可观察性
/// INotifyPropertyChanged,INotifyPropertyChanging
/// </summary>
public class ObservableObject:INotifyPropertyChanged,INotifyPropertyChanging


可以看见其实它继承了INotifyPropertyChanged,INotifyPropertyChanging这两个.net里的接口,在System.dll程序集中:

#region Assembly System.dll, v2.0.50727
// C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.dll
#endregion

namespace System.ComponentModel
{
// Summary:
//     Notifies clients that a property value has changed.
public interface INotifyPropertyChanged
{
// Summary:
//     Occurs when a property value changes.
event PropertyChangedEventHandler PropertyChanged;
}
}


当属性改变时通知客户端。这个类肯定实现了这两个接口中的事件,来看下:

/// <summary>
/// 如果需要,唤起PropertyChanged事件,非泛型
/// </summary>
/// <remarks>如果参数名在当前类的属性中不一致
/// 在DEBUG条件下抛出异常VerifyPropertyName中</remarks>
/// <param name="propertyName">改变的属性名称</param>
/// <param name="propertyName"></param>
[SuppressMessage("Microsoft.Design","CA1030:UseEventsWhereAppropriate",
Justification="This cannot be an event" )]
protected virtual void RaisePropertyChanged(string propertyName)
{
VerifyPropertyName(propertyName);

var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}


还有个就是

protected virtual void RaisePropertyChanging(string propertyName)

参数都是string类型的propertyName.

那么更好的肯定是实现这两个方法的泛型版本:

/// <summary>
/// 如果需要,唤起PropertyChanged事件,泛型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="propertyExpression"></param>
[SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate",
Justification = "This cannot be an event")]
[SuppressMessage(
"Microsoft.Design",
"CA1006:GenericMethodsShouldProvideTypeParameter",
Justification = "This syntax is more convenient(方便) than other alternatives(选择的余地)")]
protected virtual void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
{
var handler = PropertyChanged;
if (handler != null)
{
var propertyName = GetPropertyName(propertyExpression);
handler(this, new PropertyChangedEventArgs(propertyName));
}
}


注意到这里有个GetPropertyName方法:

/// <summary>
/// 根据表达式提取(Extract)属性名字
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="propertyExpression"></param>
/// <returns></returns>
protected string GetPropertyName<T>(Expression<Func<T>> propertyExpression)
{
if (propertyExpression == null)
{
throw new ArgumentNullException("propertyExpression");
}
//关于Linq的文章,可以参考
///article/5108212.html
///article/4747020.html
var body = propertyExpression.Body as MemberExpression;
if (body == null)
{
throw new ArgumentException("Invalid argument", "propertyExpression");
}

var property = body.Member as PropertyInfo;
if (property == null)
{
throw new ArgumentException("Argument is not a property","propertyExpression");
}

return property.Name;
}


关于Linq学习的博文,园子里已经有很多人写过了,可以参考lifepoemzhili的。

这个类还有两个重要的泛型方法,Set<T>:

/// <summary>
/// 把新值赋给属性,然后唤起PropertyChanged事件
/// </summary>
/// <typeparam name="T">属性类型</typeparam>
/// <param name="propertyExpression">确认属性改变的表达式,翻译有问题</param>
/// <param name="field">保存属性值的变量</param>
/// <param name="newValue">改变过后的新值</param>
/// <returns>事件只有在两个值不相等的情况下才被唤起</returns>
protected bool Set<T>(
Expression<Func<T>> propertyExpression,
ref T field,
T newValue)
{
if (EqualityComparer<T>.Default.Equals(field,newValue))
{
return false;
}

RaisePropertyChanging(propertyExpression);
field = newValue;
RaisePropertyChanged(propertyExpression);
return true;
}


另外一个其实也就是把Expression<Func<T>>参数换成string参数而已

protected bool Set<T>(
string propertyName,
ref T field,
T newValue)


之前我们的例子中的RaisePropertyChanged就是其实就是调用ViewModelBase里的RaisePropertyChanged函数,因为这个函数是虚函数,所以是调用的ViewModelBase中的RaisePropertyChanged实现:

[SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate",
Justification = "This cannot be an event")]
protected virtual void RaisePropertyChanged<T>(string propertyName, T oldValue, T newValue, bool broadcast)
{
if (string.IsNullOrEmpty(propertyName))
{
throw new ArgumentException("This method cannot be called with an empty string", "propertyName");
}

RaisePropertyChanged(propertyName);

if (broadcast)
{
Broadcast(oldValue, newValue, propertyName);
}
}


最后一个参数如果不为true,而且不注册PropertyChanged事件将不会有任何返回结果。下篇我们介绍NotificationMessage和DialogMessage的简单使用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: