Cómo: Implementar ICommandSource
En este ejemplo se muestra cómo crear un origen de comando implementando ICommandSource. Un origen de comando es un objeto que sabe cómo invocar un comando. La interfaz ICommandSource expone tres miembros: Command, CommandParameter y CommandTarget. Command es el comando que se invocará. CommandParameter es un tipo de datos definido por el usuario que se pasa desde el origen de comando al método que administra el comando. CommandTarget es el objeto en que se ejecuta el comando.
En este ejemplo, se crea una clase que crea una subclase del control Slider e implementa ICommandSource.
Ejemplo
WPF proporciona varias clases que implementan ICommandSource, como Button, MenuItem y ListBoxItem. El origen de comando define cómo invoca un comando. Los objetos Button y MenuItem invocan un comando cuando se hace clic en ellos. Un objeto ListBoxItem invoca un comando cuando se hacer doble clic en él. Estas clases sólo se convierten en el origen de un comando cuando se establece su propiedad Command.
En este ejemplo se invoca al comando cuando se mueve el control deslizante, o dicho con más exactitud, cuando se cambia la propiedad Value.
A continuación, se muestra la definición de clase.
Public Class CommandSlider
Inherits Slider
Implements ICommandSource
Public Sub New()
MyBase.New()
End Sub
public class CommandSlider : Slider, ICommandSource
{
public CommandSlider() : base()
{
}
El paso siguiente es implementar los miembros de ICommandSource. En este ejemplo, las propiedades se implementan como objetos DependencyProperty. Esto permite que las propiedades utilicen el enlace de datos. Para obtener más información sobre la clase DependencyProperty, vea Información general sobre las propiedades de dependencia. Para obtener más información sobre el enlace a datos, vea Información general sobre el enlace de datos.
Aquí se muestra únicamente la propiedad 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);
}
}
Lo siguiente es la devolución de llamada de cambio de 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);
}
El paso siguiente consiste en agregar y quitar el comando que está asociado al origen de comando. No se puede sobrescribir simplemente la propiedad Command cuando se agrega un nuevo comando, porque antes se deben quitar los controladores de eventos asociados al comando anterior, si lo hay.
' 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;
}
}
El último paso consiste en crear la lógica para el controlador de CanExecuteChanged y el método Execute.
El evento CanExecuteChanged notifica al origen de comando que es posible que haya cambiado la capacidad del comando para ejecutarse en el destino de comando actual. Cuando un origen de comando recibe este evento, normalmente llama al método CanExecute del comando. Si el comando no se puede ejecutar en el destino de comando actual, el origen de comando se suele deshabilitar. Si el comando sí se puede ejecutar en el destino de comando actual, el origen de comando se suele habilitar.
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;
}
}
}
}
El último paso es el método Execute. Si el comando es RoutedCommand, se llama al método Execute de RoutedCommand; de lo contrario, se llama al método 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);
}
}
}