如果您实现的是本身接受键盘焦点项(像文本框)的自定义控件,那么属于例外情况。在这种情形下,如果您想在控件本身嵌入命令处理且该命令处理仅在焦点项处于您的控件上时产生关联,您可实现这一目标,它的工作状况类似先前所示的 Cut 命令示例。
您也可通过 CommandTarget 属性明确指定命令处理程序来解决上述问题。例如,对于图 5 中从未启用过的窗口级 Save 按钮,您可将其命令挂接更改为如下所示:
<Button Command="Save" CommandTarget="{Binding ElementName=uc1}" Width="75" Height="25">Save</Button>
在 此代码中,Button 专门将其 CommandTarget 设为 UIElement 实例,该实例中包含一个命令处理程序。在本例中,它指定名为 uc1 的元素,该元素恰好为示例中两个用户控件实例之一。由于该元素有一个始终返回 CanExecute = true 的命令处理程序,窗口级的 Save 按钮始终处于启用状态,并仅调用该控件的命令处理程序,无论调用程序相对于命令处理程序的位置如何都是如此。
上一页 [1] [2] [3] [4] [5] [6] 下一页
超越路由命令
由于路由命令存在一定的限制,许多用 WPF 构建复杂 UI 的公司已转为使用自定义 ICommand 实现,这些实现能为它们提供自己的路由机制,特别是与可视树无关联且支持多个命令处理程序的机制。
创建自定义命令实现并不困难。针对类实现 ICommand 界面后,会为挂接命令处理程序提供一种方式,然后可在调用命令时执行路由。您还必须确定使用何种标准确定引发 CanExecuteChanged 事件的时机。
创建自定义命令时最好先使用委托。委托已支持调用目标方法,并支持多个订户。
图 6 显示了名为 StringDelegateCommand 的命令类,它使用委托来允许挂接多个处理程序。它支持向处理程序传递字符串参数,并使用调用程序的 CommandParameter 确定向处理程序传递的消息。
public class StringDelegateCommand : ICommand { Action<string> m_ExecuteTargets = delegate { }; Func<bool> m_CanExecuteTargets = delegate { return false; }; bool m_Enabled = false; public bool CanExecute(object parameter) { Delegate[] targets = m_CanExecuteTargets.GetInvocationList(); foreach (Func<bool> target in targets) { m_Enabled = false; bool localenable = target.Invoke(); if (localenable) { m_Enabled = true; break; } } return m_Enabled; } public void Execute(object parameter) { if (m_Enabled) m_ExecuteTargets(parameter != null ? parameter.ToString() : null); } public event EventHandler CanExecuteChanged = delegate { }; ...}如 您所见,我选择使