如何:实现 ICommandSource
更新:2007 年 11 月
本示例演示如何通过实现 ICommandSource 来创建命令源。 命令源是一个知道如何调用命令的对象。 ICommandSource 接口公开三个成员: Command、CommandParameter 和 CommandTarget。 Command 是将调用的命令。CommandParameter 是用户定义的数据类型,它从命令源传递到处理命令的方法。CommandTarget 是命令所作用于的对象。
在本示例中,创建这样一个类:它是 Slider 控件的子类并实现 ICommandSource。 有关完整的源代码,请参见实现接口 ICommandSource 示例。
示例
WPF 提供许多实现 ICommandSource 的类,如 Button、MenuItem 和 ListBoxItem。 命令源定义如何调用命令。Button 和 MenuItem 在被单击时调用一个命令。 ListBoxItem 在被双击时调用一个命令。这些类只有在设置了 Command 属性时才会成为命令源。
对于本示例,我们将在滑块移动时调用命令,更准确地说,是在 Value 属性更改时调用命令。
类定义如下。
public class CommandSlider : Slider, ICommandSource
{
public CommandSlider() : base()
{
}
下一步是实现 ICommandSource 成员。 在本示例中,属性实现为 DependencyProperty 对象。 这使属性可以使用数据绑定。 有关 DependencyProperty 类的更多信息,请参见依赖项属性概述。 有关数据绑定的更多信息,请参见数据绑定概述。
这里只显示 Command 属性。
// Make Command a dependency property so it can use databinding.
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(
"Command",
typeof(ICommand),
typeof(CommandSlider),
new PropertyMetadata((ICommand)null,
new PropertyChangedCallback(CommandChanged)));
public ICommand Command
{
get
{
return (ICommand)GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}
下面是 DependencyProperty 更改回调。
// Command dependency property change callback.
private static void CommandChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
CommandSlider cs = (CommandSlider)d;
cs.HookUpCommand((ICommand)e.OldValue,(ICommand)e.NewValue);
}
下一步是添加和移除与命令源关联的命令。 在添加新命令时,不能简单地改写 Command 属性,因为必须先移除与前一个命令关联的事件处理程序(如果有的话)。
// Add a new command to the Command Property.
private void HookUpCommand(ICommand oldCommand, ICommand newCommand)
{
// If oldCommand is not null, then we need to remove the handlers.
if (oldCommand != null)
{
RemoveCommand(oldCommand, newCommand);
}
AddCommand(oldCommand, newCommand);
}
// Remove an old command from the Command Property.
private void RemoveCommand(ICommand oldCommand, ICommand newCommand)
{
EventHandler handler = CanExecuteChanged;
oldCommand.CanExecuteChanged -= handler;
}
// Add the command.
private void AddCommand(ICommand oldCommand, ICommand newCommand)
{
EventHandler handler = new EventHandler(CanExecuteChanged);
canExecuteChangedHandler = handler;
if (newCommand != null)
{
newCommand.CanExecuteChanged += canExecuteChangedHandler;
}
}
最后一步是为 CanExecuteChanged 处理程序和 Execute 方法创建逻辑。
CanExecuteChanged 事件通知命令源,在当前命令目标上执行命令的能力可能已更改。 当命令源接收到此事件时,通常会对命令调用 CanExecute 方法。 如果命令无法在当前命令目标上执行,那么命令源通常会禁用自身。 如果命令可以在当前命令目标上执行,那么命令源通常会启用自身。
private void CanExecuteChanged(object sender, EventArgs e)
{
if (this.Command != null)
{
RoutedCommand command = this.Command as RoutedCommand;
// If a RoutedCommand.
if (command != null)
{
if (command.CanExecute(CommandParameter, CommandTarget))
{
this.IsEnabled = true;
}
else
{
this.IsEnabled = false;
}
}
// If a not RoutedCommand.
else
{
if (Command.CanExecute(CommandParameter))
{
this.IsEnabled = true;
}
else
{
this.IsEnabled = false;
}
}
}
}
最后一步是 Execute 方法。 如果命令是 RoutedCommand,则会调用 RoutedCommand Execute 方法;否则会调用 ICommand Execute 方法。
// If Command is defined, moving the slider will invoke the command;
// Otherwise, the slider will behave normally.
protected override void OnValueChanged(double oldValue, double newValue)
{
base.OnValueChanged(oldValue, newValue);
if (this.Command != null)
{
RoutedCommand command = Command as RoutedCommand;
if (command != null)
{
command.Execute(CommandParameter, CommandTarget);
}
else
{
((ICommand)Command).Execute(CommandParameter);
}
}
}
实现接口 ICommandSource 示例创建一个使用此命令源的示例应用程序。