此示例演示如何通过实现 ICommandSource创建命令源。 命令源是知道如何调用命令的对象。 该 ICommandSource 接口公开三个成员:
- Command:将调用的命令。
- CommandParameter:从命令源传递到处理命令的方法的用户定义数据类型。
- CommandTarget:正在执行命令的对象。
在此示例中,将创建一个从 Slider 控件继承并实现接口的 ICommandSource 类。
示例:
WPF 提供了许多实现 ICommandSource的类,例如 Button, MenuItem和 Hyperlink。 命令源定义如何调用命令。 这些类在单击命令时调用命令,并且仅在设置其 Command 属性时成为命令源。
在此示例中,当滑块移动时,或者更准确地说,当Value属性更改时,你将调用该命令。
下面是类定义:
public class CommandSlider : Slider, ICommandSource
{
public CommandSlider() : base()
{
}
Public Class CommandSlider
Inherits Slider
Implements ICommandSource
Public Sub New()
MyBase.New()
End Sub
下一步是实现 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);
}
}
' 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
下面是 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 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添加新命令时,不能简单地覆盖该属性,因为必须先删除与上一个命令关联的事件处理程序(如果有)。
// 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;
}
}
' 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
下一步是为 CanExecuteChanged 处理程序创建逻辑。
该 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;
}
}
}
}
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
最后一步是 Execute 方法。 如果该命令是一个 RoutedCommand,则 RoutedCommandExecute 调用该方法;否则,将调用该方法 ICommandExecute 。
// 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);
}
}
}
' 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