Gewusst wie: Implementieren von "ICommandSource"

In diesem Beispiel wird gezeigt, wie Sie eine Befehlsquelle durch Implementieren der ICommandSource erstellen. Eine Befehlsquelle ist ein Objekt, das über die Fähigkeit zum Aufrufen eines Befehls verfügt. Die ICommandSource-Schnittstelle macht drei Member verfügbar:

  • Command: Der Befehl, der aufgerufen wird.
  • CommandParameter: Ein benutzerdefinierter Datentyp, der von der Befehlsquelle an die Methode übergeben wird, die den Befehl behandelt.
  • CommandTarget: Das Objekt, auf das der Befehl angewendet wird.

In diesem Beispiel wird eine Klasse erstellt, die vom Slider-Steuerelement erbt und die ICommandSource-Schnittstelle implementiert.

Beispiel

WPF stellt eine Reihe von Klassen bereit, die ICommandSource implementieren, z. B. Button, MenuItem und Hyperlink. Eine Befehlsquelle definiert, wie ein Befehl aufgerufen wird. Diese Klassen rufen einen Befehl auf, wenn auf sie geklickt wird, und sie werden nur zu einer Befehlsquelle, wenn ihre Command-Eigenschaft festgelegt ist.

In diesem Beispiel rufen Sie den Befehl auf, wenn der Schieberegler verschoben wird oder genauer, wenn die Value-Eigenschaft geändert wird.

Nachfolgend sehen Sie die Klassendefinition:

public class CommandSlider : Slider, ICommandSource
{
    public CommandSlider() : base()
    {
    }
Public Class CommandSlider
    Inherits Slider
    Implements ICommandSource
    Public Sub New()
        MyBase.New()

    End Sub

Der nächste Schritt besteht im Implementieren der ICommandSource-Member. In diesem Beispiel werden die Eigenschaften als DependencyProperty-Objekte implementiert. Dadurch können die Eigenschaften Datenbindung verwenden. Weitere Informationen zur DependencyProperty-Klasse finden Sie in der Übersicht über die Abhängigkeitseigenschaften. Weitere Informationen zur Datenbindung finden Sie in der Übersicht über die Datenbindung.

Hier wird nur die Command-Eigenschaft gezeigt.

// 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

Nachfolgend sehen Sie den DependencyProperty-Änderungsrückruf:

// 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

Der nächste Schritt besteht darin, den Befehl hinzuzufügen und zu entfernen, der der Befehlsquelle zugeordnet ist. Die Command-Eigenschaft kann nicht einfach überschrieben werden, wenn ein neuer Befehl hinzugefügt wird, da die dem vorherigen Befehl zugeordneten Ereignishandler, sofern vorhanden, zuerst entfernt werden müssen.

// 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

Der nächste Schritt besteht darin, Logik für den CanExecuteChanged-Handler zu erstellen.

Das CanExecuteChanged-Ereignis teilt der Befehlsquelle mit, dass sich die Fähigkeit des Befehls zur Ausführung für das aktuelle Befehlsziel möglicherweise geändert hat. Wenn eine Befehlsquelle dieses Ereignis empfängt, ruft sie in der Regel die CanExecute-Methode für den Befehl auf. Wenn der Befehl nicht mit dem aktuellen Befehlsziel ausgeführt werden kann, deaktiviert sich die Befehlsquelle in der Regel selbst. Wenn der Befehl mit dem aktuellen Befehlsziel ausgeführt werden kann, aktiviert sich die Befehlsquelle in der Regel selbst.

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

Der letzte Schritt ist die Execute-Methode. Wenn der Befehl ein RoutedCommand ist, wird die RoutedCommandExecute-Methode aufgerufen. Andernfalls wird die ICommandExecute-Methode aufgerufen.

// 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

Weitere Informationen