【问题标题】:Base class does not implement INotifyPropertyChange; how do I implement it in derived class?基类没有实现 INotifyPropertyChange;如何在派生类中实现它?
【发布时间】:2015-07-10 20:14:26
【问题描述】:

更新: 对不起,我不清楚这个问题。我应该提到:

  1. 假设我无法更改 Base,并且..

  2. Base 中有许多属性。示例代码已简化。


这里我有一个通过网络反序列化的(基)类的对象。

public class Base
{
   public string Name { get; set; }
}

现在我希望将其属性绑定到 WPF 应用程序上,因此我在派生类上实现 INotifyPropertyChanged。

public class Derived : Base, INotifyPropertyChanged
{
  private string _derivedName;

  public string DerivedName { 
    get { return _derivedName; }
    set
    { 
      _derivedName = value;
      RaisePropertyChanged("DerivedName");
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;

  protected virtual void RaisePropertyChanged(string propertyName)
  {
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null)
    {
      handler(this, new PropertyChangedEventArgs(propertyName));
    }
  }
}

现在我的问题是:如何在 Base.Name 更改时引发属性更改事件?

我知道我可以删除继承并重新实现每个基本属性并引发事件,但是有没有更好的方法?

【问题讨论】:

  • 除非你能改变基类。
  • 当您引用 Base.Name 时,您是要拦截对该 Base 属性(名称)的更改,还是它只是代表您要拦截的许多属性。
  • @DWright 谢谢。我应该特别说我不能修改基础。基础(以及派生)实现了一个名为 IData 的接口,其中包含许多属性(名称只是其中之一)。
  • 彼得,谢谢,这澄清了。将更新我的答案。
  • 你不能。如果您无法修改 Base 并且无法覆盖该属性,则无法更改其行为。你能做的最好的事情是围绕 Base 创建一个包装类,并针对它创建一个代码消费类。

标签: c# wpf


【解决方案1】:

更改您的代码,以便 Base 实现接口,并在设置 Name 时引发事件:

public class Base : INotifyPropertyChanged
{
   private string _name;
   public string Name { get
   {
       return _name;
   }
   set{
       if(PropertyChanged != null)
           PropertyChanged(this, new PropertyChangedEventArgs("Some arg"));
       _name = value;
   }
}

   public event PropertyChangedEventHandler PropertyChanged;
}

“Derived”将继承Base的接口实现,所以只需将其从类声明中删除即可:

public class Derived : Base
{
  private string _derivedName;

  public string DerivedName { 
    get { return _derivedName; }
    set
    { 
      _derivedName = value;
      RaisePropertyChanged("DerivedName");
    }
  }

  protected virtual void RaisePropertyChanged(string propertyName)
  {
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null)
    {
      handler(this, new PropertyChangedEventArgs(propertyName));
    }
  }
}

【讨论】:

    【解决方案2】:

    创建new 修饰符以隐藏真实世界的基础并报告Name 的属性更改,例如:

    public class Derived : Base, INotifyPropertyChanged
    { 
      public new string Name
      {
        get { return base.Name; }
        set { base.Name = value;
              RaisePropertyChanged("Name");
            }
      } 
    }
    

    请参阅 MSDN:new Modifier C# Reference 了解为什么会这样。

    更新

    我知道我可以删除继承并重新实现每个基础 属性并引发事件,但有没有更好的方法?

    不...如果不执行上述修饰符,就无法在基类中的 setter 上实现 PropertyChange 调用。

    【讨论】:

    • +1 因为我认为考虑到限制,这可能是最好的选择——但它仍然可能不合适。主要需要注意的是,在对基类的引用上调用“Name”将调用Base.Name
    • @McGarnagle 想一想……即使派生类正在使用,当编译器如何访问基类强制执行修饰符?记住绑定是在对象上使用反射。如果新的修饰符正在被强制执行,则 no 可以使用基础。怎么会知道有一个基类?
    • 您总是可以将派生的实例强制转换为基类。
    • @McGarnagle 当然...但是谁负责提供绑定的实例对象列表?是的,这是可能的,但不实用。 :-)
    • dotnetfiddle.net/1G0bri。这是危险的;如果有人尝试使用基类,它会神奇地停止工作(请注意,使用这种方法与使用我认为被误解的 virtual 不同)。
    【解决方案3】:

    我会通过包装对基类属性的调用来选择更实用的方法。

    public class Derived : Base, INotifyPropertyChanged
    {
    
      public string DerivedName { 
        get { return Name; }
        set
        { 
          Name = value;
          RaisePropertyChanged("DerivedName");
          RaisePropertyChanged("Name"); //probably you will not need this line
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-06-05
      • 1970-01-01
      • 1970-01-01
      • 2011-11-04
      • 2019-07-16
      • 2021-03-28
      • 1970-01-01
      • 2012-11-24
      • 1970-01-01
      相关资源
      最近更新 更多