當我們用MVVM的時候要實現INotifyPropertyChanged,如果你是基於.net4.5以下的framework(.net4.5已有新特性我這里就不說了)
你很可能會這么寫
public class MyModel : INotifyPropertyChanged { private string _Name; public string Name { get { return _Name; } set { _Name = value; OnPropertyChanged("Name");//會造成硬編碼錯誤 } } public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }
這樣的寫法很可能會造成硬編碼錯誤
你是不是有點煩每次要寫一個字段還要寫一個屬性還要加上OnPropertyChanged,有沒好一點的方法讓我們少寫
代碼呢,能是能用現有的技術實現我們想要的像下面這樣
public class MyModel : PropertyNotifyObject { public string Name { get { return this.GetValue(x => x.Name); } set { this.SetValue(x => x.Name, value); } } }
哇!這么寫看着好簡單呀,而且還能有效避免硬編碼對你帶來的問題。
寫一個x.就能出現你要的屬性
對!這樣你就能省下更多的時間去寫加的代碼了,
先說明一下用到的技術沒有新的只是只用到了泛型和擴展方法和一點linq,要怎么實現呢?來讓我們一步一步的實現
我們先寫一個公共類方法
public class MyCommMetoh { //得到屬性的名稱 public static string GetPropertyName<T, U>(Expression<Func<T, U>> exp) { string _pName = ""; if (exp.Body is MemberExpression) { _pName = (exp.Body as MemberExpression).Member.Name; } else if(exp.Body is UnaryExpression) { _pName = ((exp.Body as UnaryExpression).Operand as MemberExpression).Member.Name; } return _pName; } }
這個GetPropertyName方法是根據一個Lambda表達式得到屬性的名稱
像這上面 this.GetValue(x => x.Name) ,這個方法就是用x => x.Name做為參數得到Name這個名字
這樣可以有效的防止硬編碼錯誤
實現一下INotifyPropertyChanged接口
public class NotifyPropertyBase : INotifyPropertyChanged { #region INotifyPropertyChanged public void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public event PropertyChangedEventHandler PropertyChanged; #endregion } public static class NotifyPropertyBaseEx { public void OnPropertyChanged<T, U>(this T npb, Expression<Func<T, U>> exp) where T : NotifyPropertyBase,new() { string _PropertyName = MyCommMetoh.GetPropertyName(exp); npb.OnPropertyChanged(_PropertyName); } }
上邊的類我想你並不陌生吧,下這那個是個擴展類,如果你不太明白那就先回去看一下基礎吧
是利用擴展根據lambda用上邊我們寫的公共類方法得到屬性的名稱,這也是為防止硬編碼而做的工作
下面才是我們真正的基類PropertyNotifyObject,這個類是我們存放數據值,修改和查詢值的
看一下我是怎么寫的
public class PropertyNotifyObject : NotifyPropertyBase,IDisposable { public PropertyNotifyObject() { } Dictionary<object, object> _ValueDictionary = new Dictionary<object, object>(); #region 根據屬性名得到屬性值 public T GetPropertyValue<T>(string propertyName) { if (string.IsNullOrEmpty(propertyName)) throw new ArgumentException("invalid " + propertyName); object _propertyValue; if(!_ValueDictionary.TryGetValue(propertyName,out _propertyValue)) { _propertyValue = default(T); _ValueDictionary.Add(propertyName, _propertyValue); } return (T)_propertyValue; } #endregion public void SetPropertyValue<T>(string propertyName, T value) { if (!_ValueDictionary.ContainsKey(propertyName) || _ValueDictionary[propertyName] != (object)value) { _ValueDictionary[propertyName] = value; OnPropertyChanged(propertyName); } } #region Dispose public void Dispose() { DoDispose(); } ~PropertyNotifyObject() { DoDispose(); } void DoDispose() { if (_ValueDictionary != null) _ValueDictionary.Clear(); } #endregion } public static class PropertyNotifyObjectEx { public static U GetValue<T, U>(this T t, Expression<Func<T, U>> exp) where T : PropertyNotifyObject { string _pN = MyCommMetoh.GetPropertyName(exp); return t.GetPropertyValue<U>(_pN); } public static void SetValue<T, U>(this T t, Expression<Func<T, U>> exp, U value) where T : PropertyNotifyObject { string _pN = MyCommMetoh.GetPropertyName(exp); t.SetPropertyValue<U>(_pN, value); } }
這是用一個字典把所有的存放了起來,看下面有一個擴展這個擴展就能讓我們實現
public string Name { get { return this.GetValue(x => Name); } set { this.SetValue(x => x.Name, value); } }
的x => x.Name。這樣就能讓我們寫完x.后就能出現我們要的屬性