Porady: implementowanie ICommandSource

W tym przykładzie pokazano, jak utworzyć źródło polecenia przez zaimplementowanie polecenia ICommandSource. Źródło polecenia to obiekt, który wie, jak wywołać polecenie. Interfejs ICommandSource uwidacznia trzy elementy członkowskie:

  • Command: polecenie, które zostanie wywołane.
  • CommandParameter: typ danych zdefiniowany przez użytkownika, który jest przekazywany ze źródła poleceń do metody obsługującej polecenie.
  • CommandTarget: obiekt, na który jest wykonywane polecenie.

W tym przykładzie tworzona jest klasa dziedziczona po kontrolce Slider i implementuje ICommandSource interfejs.

Przykład

WPF udostępnia wiele klas, które implementują ICommandSourceklasy , takie jak Button, MenuItemi Hyperlink. Źródło polecenia definiuje sposób wywoływania polecenia. Te klasy wywołują polecenie po kliknięciu i stają się źródłem poleceń tylko wtedy, gdy ich Command właściwość jest ustawiona.

W tym przykładzie wywołasz polecenie po przesunięciu suwaka lub dokładniej po Value zmianie właściwości.

Poniżej przedstawiono definicję klasy:

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

    End Sub

Następnym krokiem jest zaimplementowanie elementów ICommandSource członkowskich. W tym przykładzie właściwości są implementowane jako DependencyProperty obiekty. Dzięki temu właściwości mogą używać powiązania danych. Aby uzyskać więcej informacji na temat DependencyProperty klasy, zobacz Omówienie właściwości zależności. Aby uzyskać więcej informacji na temat powiązania danych, zobacz Omówienie powiązania danych.

W tym miejscu jest wyświetlana Command tylko właściwość .

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

Poniżej przedstawiono DependencyProperty wywołanie zwrotne zmian:

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

Następnym krokiem jest dodanie i usunięcie polecenia skojarzonego ze źródłem poleceń. Nie Command można po prostu zastąpić właściwości podczas dodawania nowego polecenia, ponieważ programy obsługi zdarzeń skojarzone z poprzednim poleceniem, jeśli istnieje, należy najpierw usunąć.

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

Następnym krokiem jest utworzenie logiki dla CanExecuteChanged programu obsługi.

Zdarzenie CanExecuteChanged powiadamia źródło polecenia, że możliwość wykonywania polecenia w bieżącym obiekcie docelowym polecenia mogła ulec zmianie. Gdy źródło polecenia odbiera to zdarzenie, zwykle wywołuje metodę CanExecute w poleceniu . Jeśli polecenie nie może zostać wykonane na bieżącym obiekcie docelowym polecenia, źródło polecenia zwykle wyłączy się. Jeśli polecenie może zostać wykonane na bieżącym obiekcie docelowym polecenia, źródło polecenia zwykle włącza się.

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

Ostatnim krokiem Execute jest metoda . Jeśli polecenie to RoutedCommand,ExecuteRoutedCommandmetoda jest wywoływana; w przeciwnym razie wywoływana ICommandExecute jest metoda .

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

Zobacz też