WPF のルーティング コマンド モデルは、コマンド、コマンド ソース、コマンドの対象、およびコマンド バインディングの 4 つの主要な概念に分けることができます。
コマンドは、実行されるアクションです。
コマンド ソースは、コマンドを呼び出すオブジェクトです。
コマンドの対象は、コマンドが実行されているオブジェクトです。
コマンド バインディングは、コマンド ロジックをコマンドに割り当てるオブジェクトです。
前の例では、Paste コマンドがコマンド、MenuItem がコマンド ソース、TextBox がコマンドの対象であり、コマンド バインディングは TextBox コントロールによって提供されています。ただし、CommandBinding が、コマンドの対象クラスであるコントロールによって必ず提供されるとは限らないことに注意してください。アプリケーション開発者が CommandBinding を作成する必要がある場合や、CommandBinding をコマンドの対象の親に割り当てる場合も多くあります。
コマンド
コマンド ソース
CommandBinding
CommandBinding は、コマンドを実装するイベント ハンドラにコマンドを関連付けます。
CommandBinding クラスには、Command プロパティと、PreviewExecuted、Executed、PreviewCanExecute、および CanExecute イベントが含まれます。
Command は、CommandBinding が関連付けられているコマンドです。PreviewExecuted イベントと Executed イベントに割り当てられたイベント ハンドラは、コマンド ロジックを実装します。PreviewCanExecute イベントと CanExecute イベントに割り当てられたイベント ハンドラは、コマンドが現在のコマンドの対象で実行可能かどうかを判断します。
アプリケーションのルート Window で CommandBinding を作成する方法を次の例に示します。CommandBinding は、Open コマンドを Executed ハンドラおよび CanExecute ハンドラに関連付けます。
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Open"
Executed="OpenCmdExecuted"
CanExecute="OpenCmdCanExecute"/>
</Window.CommandBindings>
// Creating CommandBinding and attaching an Executed and CanExecute handler
CommandBinding OpenCmdBinding = new CommandBinding(
ApplicationCommands.Open,
OpenCmdExecuted,
OpenCmdCanExecute);
this.CommandBindings.Add(OpenCmdBinding);
次に、ExecutedRoutedEventHandler および CanExecuteRoutedEventHandler を作成します。ExecutedRoutedEventHandler は、コマンドが実行されたことを知らせる文字列を表示する MessageBox を開きます。CanExecuteRoutedEventHandler は、CanExecute プロパティを true に設定します。
Private Sub OpenCmdExecuted(ByVal sender As Object, ByVal e As ExecutedRoutedEventArgs)
Dim command, targetobj As String
command = CType(e.Command, RoutedCommand).Name
targetobj = CType(sender, FrameworkElement).Name
MessageBox.Show("The " + command + " command has been invoked on target object " + targetobj)
End Sub
void OpenCmdExecuted(object target, ExecutedRoutedEventArgs e)
{
String command, targetobj;
command = ((RoutedCommand)e.Command).Name;
targetobj = ((FrameworkElement)target).Name;
MessageBox.Show("The " + command + " command has been invoked on target object " + targetobj);
}
Private Sub OpenCmdCanExecute(ByVal sender As Object, ByVal e As CanExecuteRoutedEventArgs)
e.CanExecute = True
End Sub
void OpenCmdCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
CommandBinding は、アプリケーションまたはコントロールのルート Window などの特定のオブジェクトに割り当てられます。CommandBinding が割り当てられたオブジェクトは、バインディングのスコープを定義します。たとえば、コマンドの対象の先祖に割り当てられた CommandBinding には、Executed イベントによって到達できますが、コマンドの対象の子孫に割り当てられた CommandBinding には到達できません。これは、イベントを発生させるオブジェクトから RoutedEvent がトンネリングおよびバブリングするというしくみが直接影響するからです。
場合によっては、CommandBinding は、TextBox クラスに対する Cut、Copy、Paste の各コマンドのように、コマンドの対象自体に割り当てられます。ただし、CommandBinding は、特に同じ CommandBinding を複数のコマンドの対象で使用できる場合には、メイン Window やアプリケーション オブジェクトなど、コマンドの対象の先祖に割り当てる方が便利な場合がよくあります。これらは、コマンド実行インフラストラクチャの作成時に検討される設計上の決定事項です。
コマンドの対象
コマンドの対象は、コマンドが実行される要素です。RoutedCommand のコマンドの対象は、Executed および CanExecute のルーティングが開始される要素です。前に述べたように、WPF では、ICommandSource の CommandTarget プロパティは、ICommand が RoutedCommand の場合にのみ適用されます。ICommandSource で CommandTarget が設定されていても、対応するコマンドが RoutedCommand でない場合は、コマンドの対象は無視されます。
コマンド ソースは、コマンドの対象を明示的に設定できます。コマンドの対象が定義されていない場合は、キーボード フォーカスを持つ要素がコマンドの対象として使用されます。キーボード フォーカスを持つ要素をコマンドの対象として使用する利点の 1 つは、アプリケーション開発者が同じコマンド ソースを使用して、コマンドの対象を追跡せずにコマンドを複数の対象で呼び出すことができることです。たとえば、MenuItem が TextBox コントロールと PasswordBox コントロールを持つアプリケーションで [貼り付け] コマンドを呼び出した場合、その対象は、キーボード フォーカスのあるコントロールに応じて TextBox または PasswordBox にすることができます。
マークアップと分離コードでコマンドの対象を明示的に設定する方法を次の例に示します。
<StackPanel>
<Menu>
<MenuItem Command="ApplicationCommands.Paste"
CommandTarget="{Binding ElementName=mainTextBox}" />
</Menu>
<TextBox Name="mainTextBox"/>
</StackPanel>
// Creating the UI objects
StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();
// Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);
// Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste;
CommandManager