代码之家  ›  专栏  ›  技术社区  ›  Max

如何避免实现INotifyPropertyChanged手动

  •  8
  • Max  · 技术社区  · 14 年前

    我很了解面向方面编程,但我更喜欢用面向对象的方式。

    7 回复  |  直到 14 年前
        1
  •  4
  •   leppie    14 年前

    abstract class Container : INotifyPropertyChanged
    {
      Dictionary<string, object> values;
    
      protected object this[string name]
      {
        get {return values[name]; }
        set 
        { 
          values[name] = value;
          PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
      }
    }
    
    class Foo : Container
    {
      public int Bar 
      {
        {get {return (int) this["Bar"]; }}
        {set { this["Bar"] = value; } }
      }
    }
    

    注意:非常简化的代码

        2
  •  9
  •   Marc Gravell    14 年前

    视情况而定;你可以用 PostSharp 写这样一个属性 重写 织布工;但是,我很想手动完成这项工作—也许使用一种处理数据更新的通用方法,即。

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

    public static class Notify {
        public static bool SetField<T>(ref T field, T value,
             PropertyChangedEventHandler handler, object sender, string propertyName)
        {
            if(!EqualityComparer<T>.Default.Equals(field,value)) {
                field = value;
                if(handler!=null) {
                    handler(sender, new PropertyChangedEventArgs(propertyName));
                }
                return true;
            }
            return false;
        }
    }
    
        3
  •  1
  •   Dr Herbie    14 年前

    如果没有AOP,我不认为有一种简单的方法可以将它改造成现有的类。不管你怎么做,你至少要改变你所有的属性。

    我使用继承INotifyPropertyChanged的基类和OnPropertyChanged(string propertyName)方法来触发事件。然后,我使用visualstudio代码段创建属性,这些属性在属性设置器中自动调用OnPropertyChanged。

        4
  •  1
  •   Anton    13 年前

    这里有一个类似于Marc的解决方案,它已经扩展到允许多个属性onpropertychanges和多个RaiseCanExecuteChanged

    最简单的示例用法

    string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set { OnPropertyChanged(ref _firstName, value, "FirstName"); }
    }
    

    使用多个属性更新和多个命令的高级示例

    string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set { OnPropertyChanged(ref _firstName, value, "FirstName", "FullName", Command1, Command2); }
    }
    

    高级示例对firstname和fullname调用OnProperty changed,并对command1和command2调用RaiseCanExecuteChanged

    基本视图模型代码

    protected void OnPropertyChanged<T>(ref T field, T value, params object[] updateThese)
    {
        if (!EqualityComparer<T>.Default.Equals(field, value))
        {
            field = value;
            OnPropertyChanged(updateThese);
        }
    }
    
    protected void OnPropertyChanged(params object[] updateThese)
    {
        if (PropertyChanged != null)
        {
            foreach (string property in updateThese.Where(property => property is string))
                PropertyChanged(this, new PropertyChangedEventArgs(property));
    
            foreach (DelegateCommand<object> command in updateThese.Where(property => property is DelegateCommand<object>))
                command.RaiseCanExecuteChanged();
        }
    }
    
        5
  •  0
  •   Jon Skeet    14 年前
        6
  •  0
  •   Community CDub    7 年前
        7
  •  0
  •   Ian Ringrose    13 年前

    我刚找到 ActiveSharp - Automatic INotifyPropertyChanged ,我还没用过,但看起来不错。


    发送属性更改通知 字符串。

    相反,可以这样写属性:

    public int Foo
    {
        get { return _foo; }
        set { SetValue(ref _foo, value); }  // <-- no property name here
    }
    

    请注意,不需要将属性的名称包含为字符串。ActiveSharp能够可靠而正确地自行解决这个问题。它的工作原理是,属性实现通过ref传递backing字段(\u foo)(ActiveSharp使用“by ref”调用来标识传递的是哪个backing字段,并从字段中标识属性)。