方法: ICommandSource を実装する
この例では、ICommandSource を実装してコマンド ソースを作成する方法について説明します。 コマンド ソースとは、コマンドの呼び出し方法を認識しているオブジェクトのことです。 ICommandSource インターフェイスでは、次の 3 つのメンバーが公開されます。
- 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の場合、RoutedCommand Execute メソッドが呼び出されます。それ以外の場合は、ICommand Execute メソッドが呼び出されます。
// 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
関連項目
.NET Desktop feedback