Implementing INotifyPropertyChanged - does a better way exist?

前端 未结 30 2633
感情败类
感情败类 2020-11-21 05:23

Microsoft should have implemented something snappy for INotifyPropertyChanged, like in the automatic properties, just specify {get; set; notify;} I

30条回答
  •  名媛妹妹
    2020-11-21 05:43

    Without using something like postsharp, the minimal version I use uses something like:

    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(ref T field, T value, string propertyName)
        {
            if (EqualityComparer.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"); }
        }
    }
    

    Each property is then just something like:

    private string name;
    public string Name
    {
        get { return name; }
        set { SetField(ref name, value, "Name"); }
    }
    

    which isn't huge; it can also be used as a base-class if you want. The bool return from SetField tells you if it was a no-op, in case you want to apply other logic.


    or even easier with C# 5:

    protected bool SetField(ref T field, T value,
        [CallerMemberName] string propertyName = null)
    {...}
    

    which can be called like this:

    set { SetField(ref name, value); }
    

    with which the compiler will add the "Name" automatically.


    C# 6.0 makes the implementation easier:

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

    ...and now with C#7:

    protected void OnPropertyChanged(string propertyName)
       => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    
    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 => name;
        set => SetField(ref name, value);
    }
    

    And, with C# 8 and Nullable reference types, it would look like this:

    public event PropertyChangedEventHandler? PropertyChanged;
    
    protected void OnPropertyChanged(string? propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    
    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 => name;
        set => SetField(ref name, value);
    }
    

提交回复
热议问题