C# 重构属性ChangedEventHandler

C# 重构属性ChangedEventHandler,c#,.net,wpf,C#,.net,Wpf,在我的UI代码中,我有许多具有相同基本框架的类: 派生自INotifyPropertyChanged 包含以下代码: void NotifyPropertyChanged(String info) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(info)); } } public event PropertyChangedEvent

在我的UI代码中,我有许多具有相同基本框架的类:

  • 派生自INotifyPropertyChanged
  • 包含以下代码:

    void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
    
    public event PropertyChangedEventHandler PropertyChanged;
    

这似乎是一个完美的机会,可以将其纳入一个类并从中派生,而不是INotifyPropertyChanged,但遗憾的是,C#不支持多重继承,因此它实际上不起作用。关于如何重构此类代码,您有什么想法吗?

也许您可以使用以下方法:

class A1 : INotifyPropertyChanged
{
    private string _myProperty;
    private static Expression<Func<A1, string>> myProperty = _ => _.MyProperty;

    public string MyProperty
    {
        get { return _myProperty; }
        set
        {
            _myProperty = value;
            InvokePropertyChanged(myProperty);
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void InvokePropertyChanged<T>(Expression<Func<A1, T>> property)
    {
        PropertyChangedEventHandler Handler = PropertyChanged;
        if (Handler != null)
        {
            MemberExpression expression = (MemberExpression)property.Body;
            Handler(this, new PropertyChangedEventArgs(expression.Member.Name));
        }
    }
}
public abstract class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
A1类:INotifyPropertyChanged
{
私有字符串_myProperty;

private static Expression您不能将此代码放入您的超类的超类中吗

  • 反对

    • 您的具体NotifyPropertyChanged类是4行永远不会更改的代码。创建一个代码段!

      通常的做法是让基类实现INotifyPropertyChanged,如下所示:

      class A1 : INotifyPropertyChanged
      {
          private string _myProperty;
          private static Expression<Func<A1, string>> myProperty = _ => _.MyProperty;
      
          public string MyProperty
          {
              get { return _myProperty; }
              set
              {
                  _myProperty = value;
                  InvokePropertyChanged(myProperty);
              }
          }
      
          public event PropertyChangedEventHandler PropertyChanged;
      
          private void InvokePropertyChanged<T>(Expression<Func<A1, T>> property)
          {
              PropertyChangedEventHandler Handler = PropertyChanged;
              if (Handler != null)
              {
                  MemberExpression expression = (MemberExpression)property.Body;
                  Handler(this, new PropertyChangedEventArgs(expression.Member.Name));
              }
          }
      }
      
      public abstract class ViewModelBase : INotifyPropertyChanged
      {
          public event PropertyChangedEventHandler PropertyChanged;
      
          protected void OnPropertyChanged(string propertyName)
          {
              PropertyChangedEventHandler handler = PropertyChanged;
      
              if (handler != null)
              {
                  handler(this, new PropertyChangedEventArgs(propertyName));
              }
          }
      }
      
      然后,您的类将从此类派生,当您希望通知属性值的更改时,可以调用OnPropertyChanged:

      public class PersonViewModel : ViewModelBase
      {
      
          public PersonViewModel(Person person)
          {
              this.person = person;
          }
      
          public string Name
          {
              get
              {
                  return this.person.Name;
              }
              set
              {
                  this.person.Name = value;
                  OnPropertyChanged("Name");
              }
          }
      }
      

      这可能是一个小帮助,但您可以使用params关键字,以便一次可以更改多个属性

          public event PropertyChangedEventHandler PropertyChanged;
      
          public void NotifyPropertiesChanged(params string[] Properties)
          {
              if (PropertyChanged != null)
                  foreach (string property in Properties)
                      PropertyChanged(this, new PropertyChangedEventArgs(property));
          }
      
      这将减少您在将来通知属性更改时使用的行数。因此,您可以使用:

      通知财产变更(“foo”、“bar”)

      而不是:

      通知财产变更(“foo”); NotifyPropertyChanged(“酒吧”)


      否则,我同意Anders的建议,将其移到继承树上可能是最好的。

      让topparent不要从Notify classNatrium继承,这会弄脏很多与此无关的类:(你能再解释一下吗?Sergey,这是解决依赖魔术弦的问题的许多好方法之一。我不确定这是OP问的问题,though@Anders:我的意思是,也许你不必从某个类派生,你可以很容易地手工完成它?如果不是,还有一些额外的方法:1.代码生成2.反射3。PostSharpPropFu似乎并没有解决问题,它仍然有事件+方法的复制。但它确实有一些帮助。@Anders:是的!实际上这段代码只会促进进一步的重构。你对PostSharp有什么看法?是的,我想我必须这样做。感谢MVVM的参考,很高兴知道人们知道这一点我只是对那些关于WPF(编程WPF)的书感到困惑没有提到这样的事情,或者说WPF没有一些NoTIFYPyTyTryC改类,因为它必须很快地出现,导致了丑陋的重复代码。但是,当我写到NATRIUM时,它真的是一个相当丑陋的解决方案,因为中间的类被格式化成他们不应该关心的东西。使用OOP可以做到的最好;-)Hmm.,你的意思是,中间的类被美化成他们不应该关心的东西?在你的项目中这些中产阶级负责什么?中间的帮助类可能只是有一些共同的功能。也许中间的助手类可以被推到一个单独的静态类中,一个扩展方法,或者一个帮助对象,作为一个依赖项提供给你的UI类,尽管你可能需要添加线程安全性:ValueNoTIFYPrimTyType(String Fipe){var处理程序=PrimTyType;(handler!=null){handler(this,newpropertychangedeventargs(info));}