考虑引用Josh Smith' article WPF Apps With The Model-View-ViewModel Design Pattern,特别是RelayCommand的示例实现(在图3中)。 (对于这个问题,无需通读整篇文章。)

总的来说,我认为实现非常出色,但是我对将CanExecuteChanged订阅委派给CommandManagerRequerySuggested事件有疑问。 documentation for RequerySuggested 指出:



但是RelayCommand的示例实现并未对订阅的处理程序进行任何维护:

public event EventHandler CanExecuteChanged
{
    add { CommandManager.RequerySuggested += value; }
    remove { CommandManager.RequerySuggested -= value; }
}
  • 这是否会将弱引用泄漏给RelayCommand的客户端,要求RelayCommand的用户了解CanExecuteChanged的实现并自己维护实时引用?
  • 如果是这样,例如,将RelayCommand的实现修改为类似于以下内容以减轻CanExecuteChanged订户的潜在过早GC是否有意义:
    // This event never actually fires.  It's purely lifetime mgm't.
    private event EventHandler canExecChangedRef;
    public event EventHandler CanExecuteChanged
    {
        add
        {
            CommandManager.RequerySuggested += value;
            this.canExecChangedRef += value;
        }
        remove
        {
            this.canExecChangedRef -= value;
            CommandManager.RequerySuggested -= value;
        }
    }
    
  • 最佳答案

    我也相信此实现是有缺陷的,因为它肯定会将弱引用泄漏给事件处理程序。这实际上是非常糟糕的事情。
    我正在使用MVVM Light工具箱和在其中实现的RelayCommand,它的实现方式与本文中相同。
    以下代码将永远不会调用OnCanExecuteEditChanged:

    private static void OnCommandEditChanged(DependencyObject d,
                                             DependencyPropertyChangedEventArgs e)
    {
        var @this = d as MyViewBase;
        if (@this == null)
        {
            return;
        }
    
        var oldCommand = e.OldValue as ICommand;
        if (oldCommand != null)
        {
            oldCommand.CanExecuteChanged -= @this.OnCanExecuteEditChanged;
        }
        var newCommand = e.NewValue as ICommand;
        if (newCommand != null)
        {
            newCommand.CanExecuteChanged += @this.OnCanExecuteEditChanged;
        }
    }
    

    但是,如果我这样更改它,它将起作用:

    private static EventHandler _eventHandler;
    
    private static void OnCommandEditChanged(DependencyObject d,
                                             DependencyPropertyChangedEventArgs e)
    {
        var @this = d as MyViewBase;
        if (@this == null)
        {
            return;
        }
        if (_eventHandler == null)
            _eventHandler = new EventHandler(@this.OnCanExecuteEditChanged);
    
        var oldCommand = e.OldValue as ICommand;
        if (oldCommand != null)
        {
            oldCommand.CanExecuteChanged -= _eventHandler;
        }
        var newCommand = e.NewValue as ICommand;
        if (newCommand != null)
        {
            newCommand.CanExecuteChanged += _eventHandler;
        }
    }
    

    唯一的区别?就像CommandManager.RequerySuggested文档中指出的那样,我将事件处理程序保存在一个字段中。

    关于wpf - 乔什·史密斯(Josh Smith)对RelayCommand的实现是否有缺陷?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2281566/

    10-11 22:59
    查看更多