WPF之坑——ICommandSource与RoutedUICommand

最近在项目中自己写了一个控件A,继承自contentcontrol,实现了icommandsource接口。(因需求特殊并没有使用buttonbase及它的派生类为基类),控件A在测试程序中运转良好,绑定的命令响应方法能够被正确执行。下边代码是控件A执行命令的部分:

RoutedEventArgs rea = new RoutedEventArgs(Button.ClickEvent, this);
RaiseEvent(rea);

if (!rea.Handled && Command != null)
{
    Command.Execute(CommandParameter);
}

  

但在实现项目中,我将控件A放在了另一个较为复制杂的控件B的template中,并在控件B的commandbindings中设置了命令绑定,命令使用的是WPF原生命令类型RoutedUICommand。这个时候诡异的事件发生了,不论我怎么在template里边设置控件A的commandtarget属性,上边代码执行了Command.Execute(CommandParameter)这句之后,B绑定的命令响应方法都不会被调用。

之后在群里问了一些大神,都没有得到解决方法,于是乎查了下.net码源,看看buttonbase是如何处理这个问题。

不看不知道,一看吓一跳,在buttonbase中处理命令时,用到了大量的.net项目里的internal类或方法(微软这是成心留一手啊!)

#from buttonbase.cs        
/// <summary> /// This virtual method is called when button is clicked and it raises the Click event /// </summary> protected virtual void OnClick() { RoutedEventArgs newEvent = new RoutedEventArgs(ButtonBase.ClickEvent, this); RaiseEvent(newEvent); MS.Internal.Commands.CommandHelpers.ExecuteCommandSource(this); }

  #from CommandHelpers.cs

internal static void ExecuteCommandSource(ICommandSource commandSource)
{
       CriticalExecuteCommandSource(commandSource, false);
 }


internal static void CriticalExecuteCommandSource(ICommandSource commandSource, bool userInitiated)
{
      ICommand command = commandSource.Command;
      if (command != null)
      {
           object parameter = commandSource.CommandParameter;
           IInputElement target = commandSource.CommandTarget;

           RoutedCommand routed = command as RoutedCommand;
           if (routed != null)
           {
                if (target == null)
                {
                    target = commandSource as IInputElement;
                }
                if (routed.CanExecute(parameter, target))
                {
                    routed.ExecuteCore(parameter, target, userInitiated);
                }
           }
           else if (command.CanExecute(parameter))
            {
                 command.Execute(parameter);
            }
      }
}

 从上边.net这几段代码里我们可以看到,buttonbase在执行命令里的时候,使用的是 CommandHelpers这个内部类中定义的方法,而这个方法的核心逻辑是先判断使用的命令是不是RoutedCommand类型,如果是的话则可能会使用RoutedCommand的内方法ExecuteCore去执行命令,而在这个方法中才有commandtarget这个参数。

总结一下,如果你的控件不是继承自buttonbase,那么就不能使用RoutedCommand.RoutedCommand这个内部方法,不能使用这个内部方法那么RoutedCommand就不会认你自己设置的commandtarget,那么如果.net库自己找到target不对,你再怎么设置也是徒劳。。。(我感觉被微软深深伤害了)

说明白点,不要把自己实现icommandsource的类型与routedcommand搭配使用!

原文地址:https://www.cnblogs.com/GuoRL/p/5778868.html