• WPF 4.0中ICommand.CanExecuteChanged事件订阅对象的变化


    之前基于WPF 3.0开发的应用程序有一个DelegateCommand类型,在升级至WPF 4.0后发现CanExecuteChanged事件产生通知后对应的UI并未产生变化。

      1 /// <summary>
      2 /// 委托命令
      3 /// </summary>
      4 public class DelegateCommand<T> : ICommand
      5 {
      6     /// <summary>
      7     /// 命令执行前事件
      8     /// </summary>
      9     public event EventHandler<CancelEventArgs> Executing;
     10 
     11     /// <summary>
     12     /// 命令执行后事件
     13     /// </summary>
     14     public event EventHandler Executed;
     15 
     16     private Boolean _canExecuteCache;
     17 
     18     /// <summary>
     19     /// 构造函数
     20     /// </summary>
     21     protected DelegateCommand() { }
     22 
     23     /// <summary>
     24     /// 构造函数
     25     /// </summary>
     26     /// <param name="executeActionFunc">执行函数</param>
     27     public DelegateCommand(Action<T> executeActionFunc)
     28         : this(executeActionFunc, null) { }
     29 
     30     /// <summary>
     31     /// 构造函数
     32     /// </summary>
     33     /// <param name="executeActionFunc">执行函数</param>
     34     /// <param name="canExecuteFunc">可执行函数</param>
     35     public DelegateCommand(Action<T> executeActionFunc, Func<T, Boolean> canExecuteFunc)
     36     {
     37         this.ExecuteActionFunc = executeActionFunc;
     38         this.CanExecuteFunc = canExecuteFunc;
     39     }
     40 
     41     /// <summary>
     42     /// 执行函数
     43     /// </summary>
     44     public Action<T> ExecuteActionFunc { get; protected set; }
     45 
     46     /// <summary>
     47     /// 可执行函数
     48     /// </summary>
     49     public Func<T, Boolean> CanExecuteFunc { get; protected set; }
     50 
     51     #region ICommand Members
     52 
     53     /// <summary>
     54     /// 允许执行变化事件
     55     /// </summary>
     56     public event EventHandler CanExecuteChanged;
     57 
     58     /// <summary>
     59     /// 命令是否可执行
     60     /// </summary>
     61     /// <param name="parameter">参数</param>
     62     /// <returns>是否可执行</returns>
     63     public Boolean CanExecute(Object parameter)
     64     {
     65         if (this.CanExecuteFunc == null)
     66             return true;
     67 
     68         Boolean bResult = this.CanExecuteFunc((T)parameter);
     69 
     70         if (bResult != _canExecuteCache)
     71         {
     72             _canExecuteCache = bResult;
     73 
     74             EventHandler handler = CanExecuteChanged;
     75 
     76             if (handler != null)
     77                 handler(parameter, EventArgs.Empty);
     78         }
     79 
     80         return bResult;
     81     }
     82 
     83     /// <summary>
     84     /// 执行命令
     85     /// </summary>
     86     /// <param name="parameter">参数</param>
     87     public void Execute(Object parameter)
     88     {
     89         CancelEventArgs e = new CancelEventArgs(false);
     90         EventHandler<CancelEventArgs> beforeHandler = Executing;
     91 
     92         if (beforeHandler != null)
     93             beforeHandler(parameter, e);
     94 
     95         if (!e.Cancel)
     96         {
     97             this.ExecuteActionFunc((T)parameter);
     98 
     99             EventHandler afterHandler = Executed;
    100 
    101             if (afterHandler != null)
    102                 afterHandler(parameter, e);
    103         }
    104     }
    105 
    106     #endregion
    107 }

    对于ICommand的绑定,WPF内部会订阅CanExecuteChanged事件,当对应的ICommand实现产生通知时调用CanExecute函数确认是否需要更新控件状态。调用Delegate的GetInvocationList函数发现WPF 3.0返回的Target是对应的控件(比如Button),WPF 4.0则返回CanExecuteChangedEventManager类型。在CanExecuteChangedEventManager内部它需要使用sender关联WeakEventTable获取被派发的ListenerList,而问题代码就在RaiseCanExecuteChanged时传递的sender使用了parameter:

     1 /// <summary>
     2 /// 引起允许执行变化事件
     3 /// </summary>
     4 public void RaiseCanExecuteChanged()
     5 {
     6     EventHandler handler = CanExecuteChanged;
     7 
     8     if (handler != null)
     9         handler(parameter, EventArgs.Empty);
    10 }

    修改为:

     1 /// <summary>
     2 /// 引起允许执行变化事件
     3 /// </summary>
     4 public void RaiseCanExecuteChanged()
     5 {
     6     EventHandler handler = CanExecuteChanged;
     7 
     8     if (handler != null)
     9         handler(this, EventArgs.Empty);
    10 }
  • 相关阅读:
    什么是DI
    什么是IOC?
    什么是spring框架?spring框架到底有什么用?spring框架到底做了些什么?
    JSP中动态include和静态include的区别?
    jsp静态include和动态include区别
    Request对象的主要方法有哪些?
    如何防止重复提交
    JSTL 标签大全详解
    序列化对象为xml字符串
    ASP.NET获取客户端的相关信息
  • 原文地址:https://www.cnblogs.com/junchu25/p/2733960.html
Copyright © 2020-2023  润新知