【问题标题】:Copy EventHandler in inherited class在继承的类中复制 EventHandler
【发布时间】:2016-08-12 10:10:49
【问题描述】:

我正在用 c# WPF 开发一个应用程序。

我使用一个类 PropertyChangedNotifier 来管理 INotifyPropertyChanged(请参阅 that link)。

我使用经典的 ViewModelBase :

public class ViewModelBase : INotifyPropertyChanged, IRequestClose
{
    public PropertyChangedEventHandler PropertyChanged;

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

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

在我的MainViewModel : ViewModelBase 我有一个PropertyChangedNotifier<MainViewModel> 像这样工作:

class MainViewModel : ViewModelBase
{
    private PropertyChangedNotifier<MainViewModel> _notifier;
    public new event PropertyChangedEventHandler PropertyChanged
    {
        add { _notifier.PropertyChanged += value; }
        remove { _notifier.PropertyChanged -= value; }
    }

    public MainViewModel()
    {
        _notifier = new PropertyChangedNotifier<MainViewModel>(this);
    }

    protected new void OnPropertyChanged(string propertyName)
    {
        _notifier.OnPropertyChanged(propertyName);
    }
}

但未检测到更改,当值更改时,我的 MainWindows 不会刷新(不使用 PropertyChangedNotifier 它可以工作)。我看到系统使用WindowsBase.dll!System.ComponentModel.PropertyChangedEventManager.StartListening(object source) 启动窗口,然后我看到调用 MainViewModel 的构造函数时我的 ViewModelBase.PropertyChanged 不为空。

有没有可能做这样的事情:

public MainViewModel()
{
    _notifier = new PropertyChangedNotifier<MainViewModel>(this);
    _notifier.PropertyChanged = base.PropertyChanged;
}

那会修复我的错误吗?

编辑:

来自链接的PropertyChangeNotifier:

[AttributeUsage( AttributeTargets.Property )]
public class DepondsOnAttribute : Attribute
{
    public DepondsOnAttribute( string name )
    {
        Name = name;
    }

    public string Name { get; }
}

public class PropertyChangedNotifier<T> : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public PropertyChangedNotifier( T owner )
    {
        mOwner = owner;
    }

    public void OnPropertyChanged( string propertyName )
    {
        var handler = PropertyChanged;
        if( handler != null ) handler( mOwner, new PropertyChangedEventArgs( propertyName ) );

        List<string> dependents;
        if( smPropertyDependencies.TryGetValue( propertyName, out dependents ) )
        {
            foreach( var dependent in dependents ) OnPropertyChanged( dependent );
        }
    }

    static PropertyChangedNotifier()
    {
        foreach( var property in typeof( T ).GetProperties() )
        {
            var dependsOn = property.GetCustomAttributes( true )
                                    .OfType<DepondsOnAttribute>()
                                    .Select( attribute => attribute.Name );

            foreach( var dependency in dependsOn )
            {
                List<string> list;
                if( !smPropertyDependencies.TryGetValue( dependency, out list ) )
                {
                    list = new List<string>();
                    smPropertyDependencies.Add( dependency, list );
                }

                if (property.Name == dependency)
                    throw new ApplicationException(String.Format("Property {0} of {1} cannot depends of itself", dependency, typeof(T).ToString()));

                list.Add( property.Name );
            }
        }
    }

    private static readonly Dictionary<string, List<string>> smPropertyDependencies = new Dictionary<string, List<string>>();

    private readonly T mOwner;
}

【问题讨论】:

  • PropertyChangedNotifier&lt;T&gt; 的目的是什么?为什么不简单地自己正确实现INotifyPropertyChanged
  • @LasseV.Karlsen 特别是当它已经通过从 ViewModelBase 继承实现时。 IMO,这个问题没有意义。
  • PropertyChangedNotifier 用于创建属性之间的依赖关系。如果我创建一个具有高度、宽度和周长的正方形,我可以在属性周长上设置[DependsOn("height")]。像这样,当高度发生变化时,我的 PropertyChangedNotifier 将引发周长和高度的属性变化。
  • 但是你没有暴露那个通知器?公开你只是公开你的 INotifyPropertyChanged 的​​实现,你为什么需要通知类?
  • 通知器在链接中(见第 2 行)。我的问题是:如何从上层类中复制 EventHandler ?

标签: c# wpf inotifypropertychanged


【解决方案1】:

问题是当我的MainViewModel 创建时,base.PropertyChanged 为空。调用构造函数,初始化字段/属性(一些调用 OnPropertyChanged)并在 MainView.InitializeComponent() 之后在base.PropertyChanged 中添加一个处理程序(我附加了一个调试器来查看)。此添加在 ViewModelBase 中完成,忽略 MainViewModel 中的 public new event PropertyChangedEventHandler PropertyChanged

我的想法是检查base.PropertyChanged是否被修改并复制它。

我做了这个,不知道有没有什么好主意,你觉得呢?

public class ViewModelBase : INotifyPropertyChanged, IRequestClose
{
    protected event PropertyChangedEventHandler _propertyChanged;
    protected bool propertyAdded { get; private set; }
    public event PropertyChangedEventHandler PropertyChanged
    {
        add
        {
            _propertyChanged += value;
            propertyAdded = true;
        }
        remove { _propertyChanged -= value; }
    }

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

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public Delegate[] Get_PropertyChanged()
    {
        isPropertyAdded = false;
        Delegate[] delegates = new Delegate[0];
        if (_propertyChanged != null)
        {
            delegates = _propertyChanged.GetInvocationList();
            _propertyChanged = null;
        }

        return delegates;
    }
}

class MainViewModel : ViewModelBase
{
    private PropertyChangedNotifier<MainViewModel> _notifier;
    public new event PropertyChangedEventHandler PropertyChanged
    {
        add { _notifier.PropertyChanged += value; }
        remove { _notifier.PropertyChanged -= value; }
    }

    public MainViewModel()
    {
        _notifier = new PropertyChangedNotifier<MainViewModel>(this);
    }

    protected new void OnPropertyChanged(string propertyName)
    {
        if (isPropertyAdded)
        {
            foreach (Delegate d in Get_PropertyChanged())
            {
                _notifier.PropertyChanged += (PropertyChangedEventHandler)d;
            }
        }

        _notifier.OnPropertyChanged(propertyName);
    }
}

【讨论】:

    【解决方案2】:

    对于简单的NotifyPropertyChanged("dependentProperty") 而言,这似乎是一个复杂的解决方案,尽管我确实理解设计精美解决方案的愿望。如果它具有一些性能/位置优势,那将是有意义的,但事实并非如此。它只会增加复杂性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-04-21
      • 1970-01-01
      • 1970-01-01
      • 2014-01-18
      • 2015-03-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多