Microsoft應該爲INotifyPropertyChanged
實現了一些簡單的功能,例如在自動屬性中,只需指定{get; set; notify;}
{get; set; notify;}
{get; set; notify;}
我認爲這樣作頗有意義。 仍是有任何併發症要作? git
咱們本身能夠在屬性中實現「通知」之類的功能嗎? 是否存在用於在您的類中實現INotifyPropertyChanged
的優雅解決方案,或者惟一的方法是經過在每一個屬性中引起PropertyChanged
事件。 express
若是不能,咱們能夠寫一些東西來自動生成引起PropertyChanged
事件的代碼嗎? 併發
.Net 4.5引入了新的呼叫者信息屬性。 wordpress
private void OnPropertyChanged<T>([CallerMemberName]string caller = null) { // make sure only to call this if the value actually changes var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(caller)); } }
最好在函數中添加一個比較器。 函數
EqualityComparer<T>.Default.Equals
另請參閱呼叫者信息(C#和Visual Basic) this
我實際上尚未機會本身嘗試一下,可是下一次我要創建一個對INotifyPropertyChanged有很高要求的項目時,我打算編寫一個Postsharp屬性,該屬性將在編譯時注入代碼。 就像是: google
[NotifiesChange] public string FirstName { get; set; }
會變成: spa
private string _firstName; public string FirstName { get { return _firstname; } set { if (_firstname != value) { _firstname = value; OnPropertyChanged("FirstName") } } }
我不肯定這在實踐中是否可行,我須要坐下來嘗試一下,但我不知道爲何不這樣作。 對於須要觸發多個OnPropertyChanged的狀況,我可能須要使其接受某些參數(例如,若是我在上面的類中具備FullName屬性) code
目前,我在Resharper中使用自定義模板,可是即便那樣,我也厭倦了我全部的屬性太長了。
嗯,快速的Google搜索(我在寫這篇文章以前就應該這樣作)代表,至少有一我的在這裏以前作了相似的事情。 不徹底是個人初衷,但足夠接近以證實該理論是好的。
在不使用postsharp之類的狀況下,我使用的最低版本使用的是:
public class Data : INotifyPropertyChanged { // boiler-plate public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } protected bool SetField<T>(ref T field, T value, string propertyName) { if (EqualityComparer<T>.Default.Equals(field, value)) return false; field = value; OnPropertyChanged(propertyName); return true; } // props private string name; public string Name { get { return name; } set { SetField(ref name, value, "Name"); } } }
那麼每一個屬性就像:
private string name; public string Name { get { return name; } set { SetField(ref name, value, "Name"); } }
這不是很大; 若是須要,它也能夠用做基類。 SetField
的bool
返回SetField
告訴您是否爲空操做,以防您要應用其餘邏輯。
甚至更容易使用C#5:
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null) {...}
能夠這樣稱呼:
set { SetField(ref name, value); }
編譯器將使用該"Name"
自動添加"Name"
。
C#6.0使實現更容易:
protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
...如今使用C#7:
protected void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); private string name; public string Name { get => name; set => SetField(ref name, value); }
我真的很喜歡Marc的解決方案,可是我認爲能夠略做改進,以免使用「魔術字符串」(不支持重構)。 與其使用屬性名稱做爲字符串,不如使其成爲lambda表達式:
private string name; public string Name { get { return name; } set { SetField(ref name, value, () => Name); } }
只需在Marc的代碼中添加如下方法,便可達到目的:
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression) { if (selectorExpression == null) throw new ArgumentNullException("selectorExpression"); MemberExpression body = selectorExpression.Body as MemberExpression; if (body == null) throw new ArgumentException("The body must be a member expression"); OnPropertyChanged(body.Member.Name); } protected bool SetField<T>(ref T field, T value, Expression<Func<T>> selectorExpression) { if (EqualityComparer<T>.Default.Equals(field, value)) return false; field = value; OnPropertyChanged(selectorExpression); return true; }
在這裏查看: http : //dotnet-forum.de/blogs/thearchitect/archive/2012/11/01/die-optimale-implementierung-des-inotifypropertychanged-interfaces.aspx
它是用德語編寫的,可是您能夠下載ViewModelBase.cs。 cs文件中的全部註釋均以英語編寫。
使用此ViewModelBase-Class能夠實現相似於衆所周知的Dependency Properties的可綁定屬性:
public string SomeProperty { get { return GetValue( () => SomeProperty ); } set { SetValue( () => SomeProperty, value ); } }