1

私は WPF が初めてで、.net 4.5 の Professional WPF の例を調べています。コマンドの章には、複数のコントロールが同じコマンドを送信できる例があります。Button、CheckBox、および MenuItem を使用して New コマンドをトリガーしています。

私が直面している問題は、MenuItem を初めて押すと、ソースが正しく表示されることです。ただし、Button または CheckBox をクリックした後、MenuItem をクリックすると、最後に押されたコントロール Button または CheckBox のソースが表示されます。コードの何が問題なのか、またはこの動作が WPF の MenuItem によって示される理由を見つけることができませんでした。

以下はコードです。

<Window x:Class="WpfApplication1.CommandSample"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="CommandSample" Height="300" Width="300">
  <Window.CommandBindings>
    <CommandBinding Command="New" Executed="CommandBinding_Executed" />
  </Window.CommandBindings>
  <StackPanel>
    <Button Command="New" MaxWidth="80" MaxHeight="30" Content="{x:Static ApplicationCommands.New}" />
    <Menu MaxHeight="30" VerticalAlignment="Top">
      <MenuItem Header="File">
        <MenuItem Command="New"></MenuItem>
      </MenuItem>
    </Menu>
    <CheckBox Command="New"></CheckBox>

  </StackPanel>
</Window>

namespace WpfApplication1 {
  public partial class CommandSample: Window {
    public CommandSample() {
      InitializeComponent();
    }
    private void CommandBinding_Executed(object sender,ExecutedRoutedEventArgs e)
    {
      MessageBox.Show("New Command launched by " + e.Source);
    }
  }
}
4

1 に答える 1

3

はい、これは正しいです (または、少なくともそのように設計されています)。ルーティングされたコマンドは、指定した CommandTarget に基づいてルーティングを開始します。通常、指定されていない場合、イベントを発生させるオブジェクトはそれ自体を開始点として使用します (この場合は MenuItem です)。したがって、この場合、予想どおり、ルーティングは MenuItem から始まります。そこでは何も処理しないため、CommandManager は親チェーンを上ります。FocusScope (Menu など) である要素にヒットすると、「親」FocusScope の FocusedElement (たとえば、この場合は Window である Menu の親の FocusScope) をチェックします。FocusedElement がある場合 (ボタン、チェックボックス、そのスタックパネルに配置するテキスト ボックスなど、ウィンドウのフォーカス スコープ内の要素にフォーカスすると 1 つになります。) 次に、CommandManager はその要素からイベントのルーティングを開始します。それが行われると、OriginalSource がその開始要素 (つまり、ボタン、チェックボックス、テキストボックス) である新しい ExecutedRoutedEventArgs が作成され、ツリーの上方へのルーティングが続行されます。

したがって、アプリを最初に実行したとき、ウィンドウの FocusedElement (例ではルート フォーカス スコープ) は null であるため、再ルーティングは必要ないため、CommandManager はメニューを超えて親チェーンを上に移動し続けました。それが理由です。 MenuItem が Source および OriginalSource として表示されました。ボタンをクリックすると、そのキーボード フォーカスが与えられ、その一部として、そのフォーカス スコープの論理的にフォーカスされた要素 (つまり、それを含む FocusScope の FocusedElement) にもなりました。そのため、MenuItem がその後クリックされ、CommandManager が最終的にメニューに到達すると、ボタン (またはウィンドウのフォーカススコープでフォーカスしたもの) に再ルーティングされ、そこからルーティングが開始されました。routed コマンドを使用すると、ルーティングが論理的にフォーカスされた要素を通過するようになり、たとえば、

于 2013-04-26T16:53:21.380 に答える