本示例演示如何通过实现 ICommandSource 来创建命令源。 命令源是一个知道如何调用命令的对象。 ICommandSource 接口公开三个成员:Command、CommandParameter 和 CommandTarget。 Command 是将调用的命令。 CommandParameter 是用户定义的数据类型,它从命令源传递到处理命令的方法。 CommandTarget 是命令所作用于的对象。
在本示例中,创建这样一个类:它是 Slider 控件的子类并实现 ICommandSource。
示例
WPF 提供许多实现 ICommandSource 的类,如 Button、MenuItem 和 ListBoxItem。 命令源定义其调用命令的方式。 单击 Button 和 MenuItem 时,它们就会调用命令。 ListBoxItem 在被双击时调用一个命令。 这些类只有在设置了 Command 属性时才会成为命令源。
对于本示例,我们将在滑块移动时调用命令,更准确地说,是在 Value 属性更改时调用命令。
类定义如下。
Public Class CommandSlider
Inherits Slider
Implements ICommandSource
Public Sub New()
MyBase.New()
End Sub
public class CommandSlider : Slider, ICommandSource
{
public CommandSlider() : base()
{
}
下一步是实现 ICommandSource 成员。 在本示例中,属性实现为 DependencyProperty 对象。 这使属性可以使用数据绑定。 有关 DependencyProperty 类的更多信息,请参见依赖项属性概述。 有关数据绑定的更多信息,请参见数据绑定概述。
这里只显示 Command 属性。
' Make Command a dependency property so it can use databinding.
Public Shared ReadOnly CommandProperty As DependencyProperty =
DependencyProperty.Register("Command", GetType(ICommand),
GetType(CommandSlider),
New PropertyMetadata(CType(Nothing, ICommand),
New PropertyChangedCallback(AddressOf CommandChanged)))
Public ReadOnly Property Command1() As ICommand Implements ICommandSource.Command
Get
Return CType(GetValue(CommandProperty), ICommand)
End Get
End Property
Public Property Command() As ICommand
Get
Return CType(GetValue(CommandProperty), ICommand)
End Get
Set(ByVal value As ICommand)
SetValue(CommandProperty, value)
End Set
End Property
// 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 Shared Sub CommandChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
Dim cs As CommandSlider = CType(d, CommandSlider)
cs.HookUpCommand(CType(e.OldValue, ICommand), CType(e.NewValue, ICommand))
End Sub
// 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 Sub HookUpCommand(ByVal oldCommand As ICommand, ByVal newCommand As ICommand)
' If oldCommand is not null, then we need to remove the handlers.
If oldCommand IsNot Nothing Then
RemoveCommand(oldCommand, newCommand)
End If
AddCommand(oldCommand, newCommand)
End Sub
' Remove an old command from the Command Property.
Private Sub RemoveCommand(ByVal oldCommand As ICommand, ByVal newCommand As ICommand)
Dim handler As EventHandler = AddressOf CanExecuteChanged
RemoveHandler oldCommand.CanExecuteChanged, handler
End Sub
' Add the command.
Private Sub AddCommand(ByVal oldCommand As ICommand, ByVal newCommand As ICommand)
Dim handler As New EventHandler(AddressOf CanExecuteChanged)
canExecuteChangedHandler = handler
If newCommand IsNot Nothing Then
AddHandler newCommand.CanExecuteChanged, canExecuteChangedHandler
End If
End Sub
// 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 Sub CanExecuteChanged(ByVal sender As Object, ByVal e As EventArgs)
If Me.Command IsNot Nothing Then
Dim command As RoutedCommand = TryCast(Me.Command, RoutedCommand)
' If a RoutedCommand.
If command IsNot Nothing Then
If command.CanExecute(CommandParameter, CommandTarget) Then
Me.IsEnabled = True
Else
Me.IsEnabled = False
End If
' If a not RoutedCommand.
Else
If Me.Command.CanExecute(CommandParameter) Then
Me.IsEnabled = True
Else
Me.IsEnabled = False
End If
End If
End If
End Sub
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 Overrides Sub OnValueChanged(ByVal oldValue As Double, ByVal newValue As Double)
MyBase.OnValueChanged(oldValue, newValue)
If Me.Command IsNot Nothing Then
Dim command As RoutedCommand = TryCast(Me.Command, RoutedCommand)
If command IsNot Nothing Then
command.Execute(CommandParameter, CommandTarget)
Else
CType(Me.Command, ICommand).Execute(CommandParameter)
End If
End If
End Sub
// 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);
}
}
}