9

特定のコマンドを処理するために CommandBindings コレクションに CommandBinding を追加する UserControl があります。後で、このコントロールをウィンドウで使用し、同じコントロールに別のバインディングを追加して、追加の動作を追加したいと考えています。ただし、問題は、これを行うと、別の CommandBinding をコントロールの CommandBindings コレクションに追加すると、同じコマンドに対して既に作成されているバインディングが置き換えられるように見えることです。コントロールは、コントロールごとに 1 つの CommandBinding しか持つことができないように見えますが、これは正しいですか?

同じ保存コマンドに対して 2 つの CommandBinding を設定しようとする以下のコード例を参照してください。

<Window x:Class="MultipleCommandBindings.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.CommandBindings>
    <CommandBinding Command="Save"
                    Executed="CommandBinding_Executed" />
    <CommandBinding Command="Save"
                    Executed="CommandBinding_Executed" />
</Window.CommandBindings>
<Grid>
    <Button Height="23"
            HorizontalAlignment="Right"
            Margin="0,0,25,88"
            Name="button1"
            VerticalAlignment="Bottom"
            Width="75"
            Command="Save">Button</Button>
</Grid>

もともと、このコードを書いたとき、コンパイル時または実行時例外のいずれかを予期していましたが、文句を言わなかったことに驚きました。次に、 CommandBinding_Executed ハンドラーが 2 回ではなく 1 回しか呼び出されないので、期待していたのにがっかりしました。

更新: 少しテストした後、2 番目の CommandBinding が最初の CommandBinding を上書きしていないように見えますが、代わりに、イベント ハンドラーで Handled を true に設定していなくても、最初のコマンド バインディングが Command を飲み込んでいるように見えます。この時点で、私の問題の解決策は、Handled が true に設定されていない場合でも、ルーティングされたコマンドが最初のハンドラーを超えて伝播しない理由を理解することであると確信しています。

更新: WPF でのコマンド ルーティングの背後にある奇妙な動作のいくつかを確認する、このちょっとした情報を 見つけました。

更新: コマンドごとに 1 つの有効な CommandBinding しか存在できないように見えるという事実を回避する方法についての 1 つの考えは、デフォルトの CommandBinding クラスが Executed および CanExecute をイベントとして公開しているように見えることです。もちろん、すべてのイベントと同様に複数のハンドラーを持つことができます。 . その場合のアイデアは、標準の CommandBindings.Add メソッド以外の方法を使用して、追加のハンドラーをコマンドに追加することです。おそらく、これは Control クラスの拡張メソッドを介して実行でき、カスタムの CompositeCommandBinding クラスと組み合わせて、1 つのメイン バインディング内に複数のバインディングを集約できます。

4

2 に答える 2

3

これまでのところ、論理ツリーの2つの異なるレベルでコマンドを処理するという、この問題の回避策を思い付くことができました。以下の例では、グリッド内で[保存]コマンドを処理し、次にWindow要素内でも処理します。

<Window x:Class="MultipleCommandBindings.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.CommandBindings>
    <CommandBinding Command="Save"
                    Executed="CommandBinding_Executed2"/>
</Window.CommandBindings>
<Grid>
    <Grid.CommandBindings>
        <CommandBinding Command="Save"
                        Executed="CommandBinding_Executed1" />
    </Grid.CommandBindings>

    <Button Height="23"
            HorizontalAlignment="Right"
            Margin="0,0,25,88"
            Name="button1"
            VerticalAlignment="Bottom"
            Width="75"
            Command="Save">Button</Button>
</Grid>

これを機能させるには、コードビハインドでコマンド実行を次のレベルに手動で伝播する必要もあります。

    private void CommandBinding_Executed1(object sender, ExecutedRoutedEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("Executed 1!");
        var command = e.Command as RoutedUICommand;
        command.Execute(e.Parameter, this);
    }

    private void CommandBinding_Executed2(object sender, ExecutedRoutedEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("Executed 2!");
    }

コマンドを監視してツリー上に自然に伝播させる方法について誰かがもっと良いアイデアを持っている場合は、それを見てみたいと思います。そうでない場合は、この回避策に頼るかもしれません。

于 2010-02-18T21:03:17.740 に答える
1

あなたの質問に対する答えはわかりませんが、Reflector を使用することは合理的に思えます。

なぜこんなことをしているのだろう?コマンドバインディングを組み合わせようとするよりも、複合パターンを使用して動作を集約する方が理にかなっているのではないでしょうか?

于 2010-02-18T17:15:01.013 に答える