c# - CommandBinding 使用自定义 ICommand 实现时未调用已执行的事件处理程序
问题描述
我试图理解 RoutedUICommand 的工作原理。我曾在 Wpf 中使用过 MVVM,并试图了解 ICommand 实现实际上在 wpf 中有效。但是,我无法理解一些事情。
public class RelayCommand : ICommand
{
private Action<Task> callBack;
private bool runOnUi;
private Action<object> whatToExecute;
private Func<object, bool> whenToExecute;
public RelayCommand(Func<object, bool> whenToExecute, Action<object> whatToExecute,
bool runOnUi = true, Action<Task> callBack = null)
{
this.whenToExecute = whenToExecute;
this.whatToExecute = whatToExecute;
this.runOnUi = runOnUi;
this.callBack = callBack;
}
/// <summary>
/// This is an event from Interface
/// </summary>
public event EventHandler CanExecuteChanged;
/// <summary>
/// Decides whether the command can execute or not.
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
public bool CanExecute(object parameter)
{
if (this.whenToExecute != null)
{
try
{
return this.whenToExecute(parameter);
}
catch
{
return false;
}
}
return true;
}
/// <summary>
/// Called when CanExecute is true and command is fired.
/// </summary>
/// <param name="parameter"></param>
public void Execute(object parameter)
{
if (this.whatToExecute != null)
{
if (this.runOnUi)
{
this.whatToExecute(parameter);
}
else
{
var parallelTask = Task.Run(() =>
{
this.whatToExecute(parameter);
});
if (this.callBack != null)
parallelTask.ContinueWith(this.callBack);
}
}
}
}
这是 ICommand 接口的自定义实现。我在标签的上下文菜单中添加了两个菜单项。首先是 ApplicationCommands.Close,其次是我的客户 RelayCommand 类型。
this.Label1.ContextMenu = new ContextMenu();
var menuItem1 = new MenuItem();//Source
menuItem1.Command = ApplicationCommands.Close; //Command
var commandBindingObject = new CommandBinding(menuItem1.Command);
commandBindingObject.CanExecute += this.MenuItem1Close_CanExecute;
commandBindingObject.Executed += this.MenuItem1Close_Executed;
menuItem1.CommandBindings.Add(commandBindingObject);
var menuItem2 = new MenuItem();//Source
menuItem2.Header = "Custom Command";
menuItem2.Command = new RelayCommand(o =>
{
return true;
},
o =>
{
}); //Command
var commandBindingObject2 = new CommandBinding(menuItem2.Command);
commandBindingObject2.CanExecute += this.MenuItem2Close_CanExecute;
commandBindingObject2.Executed += this.MenuItem2Close_Executed;
menuItem2.CommandBindings.Add(commandBindingObject2);
this.Label1.ContextMenu.Items.Add(menuItem1);
this.Label1.ContextMenu.Items.Add(menuItem2);
每当我单击第一个菜单项处理程序时,都会调用 menuitem1 处理程序,但不会调用 menuitem2。我只是想了解命令模式是如何在 wpf 中实现的,因此除此之外,任何指向此类的链接也会有很大帮助。
解决方案
路由命令
该ApplicationCommands.Close
命令是一个RoutedUICommand
. 路由命令引发遍历元素树直到找到命令绑定的路由事件PreviewExecuted
。Executed
如果找到一个,ExecutedRoutedEventHandler
则调用相应的。如果menuItem1
执行的处理程序是MenuItem1Close_Executed
. 这同样适用于PreviewCanExecute
andCanExecute
事件和MenuItem1Close_CanExecute
处理程序 as CanExecuteRoutedEventHandler
。
中继命令
您menuItem2
使用RelayCommand
. CanExecute
这种类型的命令使用and的委托Execute
,而不是遍历元素树来搜索命令绑定。
在您的情况下,以下几行是不必要的。
var commandBindingObject2 = new CommandBinding(menuItem2.Command);
commandBindingObject2.CanExecute += this.MenuItem2Close_CanExecute;
commandBindingObject2.Executed += this.MenuItem2Close_Executed;
menuItem2.CommandBindings.Add(commandBindingObject2);
whenToExecute
而是为and传递方法或匿名方法whatToExecute
。
menuItem2.Command = new RelayCommand(CanExecute, Execute);
你不能通过MenuItem1Close_CanExecute
或MenuItem1Close_Executed
在这里,因为他们有不兼容的签名:
void CanExecuteRoutedEventHandler(object sender, CanExecuteRoutedEventArgs e)
void ExecutedRoutedEventHandler(object sender, ExecutedRoutedEventArgs e)
CanExecute
必须是Func<object, bool>
并且Execute
必须是Action<object>
代表。
bool CanExecute(object obj)
void Execute(object obj)
推荐阅读
- r - 如何使用 dplyr 在 R 中重新编码多项选择答案?
- spring-boot - 如何在 Spring Boot 中使用 Apache James 创建邮件服务器?
- android - 在 AndroidStudio 中设置没有 gradle 的 jniLibs
- php - MYSQL - 获取列的 NULL 记录,以及同一列的 1 个以上 COUNT 的记录
- c++ - c++ 类包含一个与自身类型相同的静态成员。为什么是这种模式?
- c# - 通过 ServerCertificateCustomValidationCallback 验证后使 X509Certificate2 可访问
- node.js - Nuxt,Express,套接字无法连接
- botframework - 如何使用 botbuilder-ai sdk 在 nodejs 中为 QnA 使用 strictFilters 参数
- opencv - opencv2/intensity_transform.hpp:没有这样的文件或目录
- visual-studio-2010 - 调试构建无法在其他机器上执行