WPF:“ApplicationCommands.New”在MenuItem的情况下显示不正确的Source

时间:2013-04-26 16:04:21

标签: wpf menuitem

我是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);
    }
  }
}

1 个答案:

答案 0 :(得分:2)

是的,这是正确的(或者至少它是如何设计的)。路由命令根据您指定的CommandTarget开始路由。如果未指定一个,则引发事件的对象将自身用作起点(在本例中为MenuItem)。因此,在这种情况下,路由从MenuItem开始,如您所料。什么都没有处理它,所以CommandManager上升到父链。当它击中一个FocusScope元素(如菜单)时,它会检查“父”FocusScope的FocusedElement(例如,Menu的父级的FocusScope,在这种情况下是Window)。如果有一个FocusedElement(一旦你将一个元素聚焦在窗口的焦点范围内,例如你的按钮,复选框,你可能放在那个堆栈面板中的文本框等),那么CommandManager就会开始路由事件。那个元素。当它这样做时,它会创建一个新的ExecutedRoutedEventArgs,其中OriginalSource是起始元素(所以按钮,复选框,文本框),然后继续向上路由树。

因此,当您第一次运行应用程序时,窗口的FocusedElement(在您的示例中是根焦点范围)为null,因此不需要重新路由,因此CommandManager只是继续通过菜单运行父链并且这就是为什么MenuItem出现作为源和&amp; OriginalSource。单击按钮时,您给出了键盘焦点,并且作为其一部分也成为其焦点范围的逻辑焦点元素(即包含FocusScope的FocusedElement)。因此,当随后单击MenuItem并且CommandManager最终到达菜单时,它会重新路由到Button(或者您在窗口的focusscope中聚焦的任何内容)并从那里开始路由。我说这是预期的,因为使用路由命令你希望路由通过逻辑上聚焦的元素,这样,例如,菜单项的剪切命令将触发窗口中具有焦点的TextBox的剪切。