如何最好地调用INotifyPropertyChanged的PropertyChanged事件?

10

当您实现INotifyPropertyChanged接口时,每次在类中更新属性时,您都需要负责调用PropertyChanged事件。

这通常会导致以下代码:

    public class MyClass: INotifyPropertyChanged

        private bool myfield;
        public bool MyField
        {
            get { return myfield; }
            set
            {
                if (myfield == value)
                    return;
                myfield = value;
                OnPropertyChanged(new PropertyChangedEventArgs("MyField"));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            PropertyChangedEventHandler h = PropertyChanged;
            if (h != null)
                h(this, e);
        }
   }

那就是每个属性有12行

如果可以像这样装饰自动属性就会简单得多:

[INotifyProperty]
public double MyField{ get; set; }

但是不幸的是,这是不可能的(请参见msdn上的此帖子作为例子)

我如何减少每个属性所需的代码量?


请参考https://dev59.com/S3M_5IYBdhLWcg3wjj4p#1333874,了解一种经过编译器检查的实现INotifyPropertyChanged的方法。避免将属性名称作为魔术字符串。 - Ian Ringrose
此外,如果您使用IoC容器,可以在运行时编织样板代码:https://dev59.com/cHRB5IYBdhLWcg3w2613(警告:如果不熟悉IoC,这将扭曲您的思维)。 - fostandy
补充一下:PostSharp 现在已经支持这个了。 - It'sNotALie.
一个更近期(也非常受欢迎)的答案可以在这里找到:https://dev59.com/bHM_5IYBdhLWcg3wlEPO - kmote
3个回答

7
实际上,每个属性只有3-4行其他行分摊在所有“通知”属性上:
class Person : INotifyPropertyChanged
{
    #region INotifyPropertyChanged: Shared bit
    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, e);
    }
    #endregion

    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            if (_firstName == value)
                return;
            _firstName = value;
            OnPropertyChanged(new PropertyChangedEventArgs("FirstName"));
        }
    }

    // Ditto for other properties
}

您可以尝试以下方式,这样可以分担更多的负荷:
private string _firstName;
public string FirstName
{
    get { return _firstName; }
    set { SetNotifyingProperty("FirstName", ref _firstName, value); }
}
private void SetNotifyingProperty<T>(string propertyName,
                                     ref T field, T value)
{
    if (value.Equals(field))
        return;
    field = value;
    OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}

好主意。顺便说一下,那段代码的另一个问题是每次属性更改时都会创建一个新的PropertyChangedEventArgs实例。可以将EventArgs存储在成员变量中以供以后使用。 - Brann

2

目前我所做的是在我的类中编写以下内容:

 //AUTOGENERATE INotifyProperty
 private bool myfield;

我写了一个小工具,可以在部分类中生成所有需要的属性代码。虽然这并不是一种优雅的解决方案,但它可以正常工作 :)


1

最合理的做法是外包。

编写一个类(ObservableObject),其中包含以下代码:

class ObservableObject : INotifyPropertyChanged
{
  public event PropertyChangedEventHandler PropertyChanged;

  protected void OnPropertyChanged(string name)
  {
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
  }
}

所有从这个类派生的类都可以通过 protected 访问该方法。
例子:
class Example : ObservableObject
{
  //propfull
  private string name;
  public string Name
  {
    get {return name;}
    set 
    {
      name = value;
      OnPropertyChanged(nameof(Name));
    }
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接