2

「WPFコントロール開発」ブックのデフォルトのコマンドターゲットの役割を果たす要素については、次の2つの異なるアイデアがあります。

258ページ»コマンドターゲットは、コマンドが発生するオブジェクトです。ICommandSourceインターフェイスには、特定のオブジェクトに設定できるCommandTargetプロパティが含まれています。デフォルトでは、コマンドソース自体がコマンドターゲットと見なされます。

262ページ» デフォルトでは、CommandTargetが設定されていない場合、キーボードフォーカスのある要素が使用されます。

さらに、このチュートリアルでは、メニュー項目とボタンのコマンドターゲットを未定義のままにしておくことができますが、メニュー項目のみ(つまり、ボタンではなく)がコマンドターゲットを真に検出できます。では、デフォルトのコマンドターゲットは何ですか?!

4

4 に答える 4

5

いくつかの異なるテストケースに基づいて、@ dowhileforと@hbarckの回答に関して、私はそれぞれのケースに特定の移動経路があると結論付けました。

指定されたCommandTarget:CommandTargetコマンドをバインドした最初の(最も近い)要素を見つけるために、ビジュアルツリーのルート要素に向かって開始します。(このパスでのみこの要素を検索します。)結論:

  1. 送信者:コマンドをバインドしたCommandTargetコンテナ要素(with CommandBinding)。
  2. e.source:として指定された要素CommandTarget

未指定のCommandTarget:(スコープで)フォーカスされたCommandSource要素からビジュアルツリーのルート要素に向かって開始し、コマンドをバインドした最初の(最も近い)要素を見つけます。この状態で、フォーカスされた要素はとして決定されCommandTargetます。結論:

  1. 送信者:コマンドをバインドしたフォーカスされた要素のコンテナー(CommandBindingタグ付き)。
  2. e.Source:フォーカスされた要素。
于 2012-05-13T06:19:03.563 に答える
2

文脈から外れて、最初に強調表示された文が何を意味するのか理解できませんが、それは間違っていると思います。一方、2番目の文は正しいです

Msdn:

コマンドターゲットが定義されていない場合、キーボードフォーカスのある要素がコマンドターゲットとして使用されます。

これは、現在フォーカスされているテキストボックスへの貼り付けコマンドなど、コマンドを何かに対して操作する場合に便利です。どのテキストボックスまたは他のどのコントロールにフォーカスがあるかに関係なく、貼り付けコマンドを常に機能させる必要があります。これにより、これが可能になります。メニューに関しては、 FocusScopeと呼ばれる覚えておくべき別の概念があることを指摘する価値があります。WPFでのコマンドは難しい場合があります。テキストボックスのフォーカスを取得しない保存ボタンを検討してください。したがって、Textプロパティは更新されません(focuslostのターゲットバインディングのみが更新されるため)。ただし、「単純な」ICommandではなく、でCommandTargetのみ機能することを忘れないでください。RoutedCommands

チュートリアルビデオに関しては、まだ見ていません。この概念は、キーボードフォーカス自体を使用しないすべてのCommandSourceで機能します。

結論として、CommandTargetは、コマンドがRoutedCommandである限り、現在のキーボードフォーカス要素であり、それ以外の場合は無視されます。

于 2012-05-12T13:23:16.023 に答える
1

ここで1つのポイントが欠落しているようです。特定のコマンドのCommandTargetは、そのコマンドのCommandBindingを定義するオブジェクトにしかなれません。

編集:システムに誤解を招く情報を残さないように、次の段落を明確にして修正しました。

コマンドルーティングは、イベントルーティングの特殊なケースです。つまり、論理ツリーを上下に移動するイベントです。InputBindings、Buttons、MenuItemsなどのICommandSourceインターフェイスを実装するコントロールは、CommandSourcesです。コマンドを発生させると、RoutedEventがCommandTargetで開始されます。これは通常、キーボードフォーカスを持つ要素です。イベントは、ルートに到達するまで論理ツリーを上に移動します。この方法でコマンドのCommandBindingsを持つすべての要素は、コマンドを処理する機会を取得しますが、通常、コマンドを処理する最初の要素が優先され、ルーティングプロセスが停止します。コマンドのCommandBindingがある場合、これはCommandSource自体である可能性もあり、おそらくそれが最初の引用です。要素がイベントを処理する場合、

混乱を完全にするために、ICommandSourceインターフェイスはCommandTargetと呼ばれるプロパティを定義します。このプロパティは、コマンドルーティングを短絡し、キーボードのフォーカスがどこにあっても、コマンドを処理するための特別なコントロールが必要な場合に使用します。この場合、問題のButtonまたはMenuItemにCommandTarget = "{Binding ElementName=MyCommandTargetControl}"のようなものを記述します。この場合も、このコントロールにコマンドのCommandBindingが含まれていることを確認する必要があります。そうでない場合、コマンドは永続的に無効になります。

于 2012-05-12T15:15:30.317 に答える
1

私はこれが何を意味するのか理解したと思います:

要素がフォーカス可能である場合、未定義のルーティングされたコマンドターゲットを自動的に検出することはできません。

要素がフォーカス可能である場合、それは、コマンドを上げるためにアクティブ化されたときに常にキーボードフォーカスを持っていることを意味します。したがって、コマンドのCommandBindingがある場合は常にそれ自体を処理し、ない場合は常に無効になります。

ただし、このXAMLのように、コントロールのコンテナーでFocusManager.IsFocusScopeをtrueに設定することで、これを回避できます。

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:my="clr-namespace:CommandRouting"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Menu IsMainMenu="True">
            <MenuItem x:Name="TestMenuItem" Command="{x:Static my:MainWindow.TestCommand}"/>
        </Menu>
        <GroupBox x:Name="CommandBindingOnControlsGroupBox" Header="CommandBinding on Controls" Grid.Row="1">
            <StackPanel>
            <Button x:Name="CommandBindingOnButtonButton" Command="{x:Static my:MainWindow.TestCommand}" Content="CommandBinding on Button">
               <Button.CommandBindings>
                    <CommandBinding Command="{x:Static my:MainWindow.TestCommand}" Executed="CommandBinding_Executed" PreviewExecuted="CommandBinding_Executed"/>
                </Button.CommandBindings>
            </Button>
                <TextBox x:Name="CommandBindingOnTextBoxTextBox">
                    <TextBox.CommandBindings>
                        <CommandBinding Command="{x:Static my:MainWindow.TestCommand}" Executed="CommandBinding_Executed"/>
                    </TextBox.CommandBindings>
                    <TextBox.InputBindings>
                        <!-- provide alternate keyboard shortcut -->
                        <KeyBinding Key="{x:Static Key.P}" Modifiers="{x:Static ModifierKeys.Control}" Command="{x:Static my:MainWindow.TestCommand}"/>
                    </TextBox.InputBindings>
                </TextBox>
                <Button x:Name="CommandTargetOnButtonButton" Command="{x:Static my:MainWindow.TestCommand}" Content="CommandTarget on Button" CommandTarget="{Binding ElementName=CommandBindingOnControlsGroupBox}">
                    <Button.CommandBindings>
                        <CommandBinding Command="{x:Static my:MainWindow.TestCommand}" Executed="CommandBinding_Executed"/>
                    </Button.CommandBindings>
                </Button>
            </StackPanel>
        </GroupBox>
        <GroupBox x:Name="CommandBindingOnContainerGroupBox" Header="CommandBinding on Container" Grid.Row="2">
            <GroupBox.CommandBindings>
                <CommandBinding Command="{x:Static my:MainWindow.TestCommand}" PreviewExecuted="CommandBinding_Executed"/>
            </GroupBox.CommandBindings>
            <StackPanel x:Name="CommandBindingOnInnerContainerStackPanel">
                <StackPanel.CommandBindings>
                    <CommandBinding Command="{x:Static my:MainWindow.TestCommand}" Executed="CommandBinding_Executed"/>
                </StackPanel.CommandBindings>
                <Button x:Name="CommandBindingOnContainerButton" Command="{x:Static my:MainWindow.TestCommand}" Content="CommandBinding on Two Containers">
                </Button>
                <TextBox x:Name="CommandBindingOnContainerTextBox">
                    <TextBox.InputBindings>
                        <!-- provide alternate keyboard shortcut -->
                        <KeyBinding Key="{x:Static Key.P}" Modifiers="{x:Static ModifierKeys.Control}" Command="{x:Static my:MainWindow.TestCommand}"/>
                    </TextBox.InputBindings>
                </TextBox>
            </StackPanel>
        </GroupBox>
        <GroupBox x:Name="OtherFocusScopeGroupBox" FocusManager.IsFocusScope="True" Header="Other FocusScope, No CommandBindings" Grid.Row="3">
            <StackPanel >
                <Button x:Name="OtherFocusScopeButton" Command="{x:Static my:MainWindow.TestCommand}" Content="Other FocusScope">
                </Button>
                <TextBox x:Name="OtherFocusScopeTextBox">
                    <TextBox.CommandBindings>
                        <CommandBinding Command="{x:Static my:MainWindow.TestCommand}" Executed="CommandBinding_Executed"/>
                    </TextBox.CommandBindings>
                    <TextBox.InputBindings>
                        <!-- provide alternate keyboard shortcut -->
                        <KeyBinding Key="{x:Static Key.P}" Modifiers="{x:Static ModifierKeys.Control}" Command="{x:Static my:MainWindow.TestCommand}"/>
                    </TextBox.InputBindings>
                </TextBox>
            </StackPanel>
        </GroupBox>
    </Grid>
</Window>
于 2012-05-13T12:16:25.733 に答える