方法 : ICommandSource を実装する

この例では、ICommandSource を実装してコマンド ソースを作成する方法を示します。 コマンド ソースは、コマンドを呼び出す方法を認識しているオブジェクトです。 ICommandSource インターフェイスは、CommandCommandParameter、および CommandTarget の 3 つのメンバーを公開します。 Command は、呼び出されるコマンドです。 CommandParameter は、コマンド ソースからコマンドを処理するメソッドに渡されるユーザー定義のデータ型です。 CommandTarget は、コマンドが実行されているオブジェクトです。

この例では、Slider コントロールをサブクラス化し、ICommandSource を実装するクラスが作成されます。

使用例

WPF は、ButtonMenuItemListBoxItem などの ICommandSource を実装するさまざまなクラスを提供します。 コマンド ソースは、コマンドを呼び出す方法を定義します。 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);
        }
    }
}

参照

参照

ICommandSource

ICommand

RoutedCommand

概念

コマンド実行の概要