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 ); } }