如何在C#6.0中实现INotifyPropertyChanged?

这个问题的答案已被编辑,说在C#6.0中,可以使用以下OnPropertyChanged过程实现INotifyPropertyChanged:

protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } 

但是,从该答案中不清楚相应的属性定义应该是什么。 使用此构造时,在C#6.0中完整实现INotifyPropertyChanged是什么样的?

在合并各种更改后,代码将如下所示。 我用评论突出显示了改变的部分以及每个部分的帮助

 public class Data : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { //C# 6 null-safe operator. No need to check for event listeners //If there are no listeners, this will be a noop PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } // C# 5 - CallMemberName means we don't need to pass the property's name protected bool SetField(ref T field, T value, [CallerMemberName] string propertyName = null) { if (EqualityComparer.Default.Equals(field, value)) return false; field = value; OnPropertyChanged(propertyName); return true; } private string name; public string Name { get { return name; } //C# 5 no need to pass the property name anymore set { SetField(ref name, value); } } } 

我在我的项目中使用相同的逻辑。 我的应用程序中的所有视图模型都有一个基类:

 using System.ComponentModel; using System.Runtime.CompilerServices; public class PropertyChangedBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } 

每个视图模型都inheritance自此类。 现在,在每个属性的setter中我只需要调用OnPropertyChanged()

 public class EveryViewModel : PropertyChangedBase { private bool initialized; public bool Initialized { get { return initialized; } set { if (initialized != value) { initialized = value; OnPropertyChanged(); } } } 

它为什么有效?

[CallerMemberName]由编译器自动填充,并调用此函数的成员名称。 当我们从Initialized调用nameof(Initialized) ,编译器将nameof(Initialized)作为参数放入nameof(Initialized)

要记住的另一个重要细节

该框架要求PropertyChanged和您绑定的所有属性都是public

我知道这个问题很老,但这是我的实施

Bindable使用字典作为属性存储。 为子类添加必要的重载以使用ref参数管理自己的后备字段非常容易。

  • 没有神奇的绳子
  • 没有反思
  • 可以改进以抑制默认字典查找

代码:

  public class Bindable : INotifyPropertyChanged { private Dictionary _properties = new Dictionary(); ///  /// Gets the value of a property        ///  ///  ///  protected T Get([CallerMemberName] string name = null) { object value = null; if (_properties.TryGetValue(name, out value)) return value == null ? default(T) : (T)value; return default(T); } ///  /// Sets the value of a property ///  ///  ///  ///  protected void Set(T value, [CallerMemberName] string name = null) { if (Equals(value, Get(name))) return; _properties[name] = value; OnPropertyChanged(name); } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } 

像这样使用

 public class Item : Bindable { public Guid Id { get { return Get(); } set { Set(value); } } }