当焦点在文本框上时,WPF应用程序菜单被禁用,并且在应用程序重新启动之前不会工作
我的示例WPF应用程序中的AppMenus有问题 Window2.xaml:当焦点在文本框上时,WPF应用程序菜单被禁用,并且在应用程序重新启动之前不会工作,wpf,commandbinding,Wpf,Commandbinding,我的示例WPF应用程序中的AppMenus有问题 Window2.xaml: <Window x:Class="SampleWpfApp.Window2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:SampleWpf
<Window x:Class="SampleWpfApp.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SampleWpfApp"
Name="RootWindow"
Title="Window2" Height="600" Width="800">
<Window.InputBindings>
<KeyBinding Gesture="CTRL+N" Command="ApplicationCommands.New" CommandTarget="{Binding ElementName=TopMenu}" />
<KeyBinding Gesture="CTRL+F1" Command="{x:Static local:TopMenu.ShowHelp}" CommandTarget="{Binding ElementName=TopMenu}" />
</Window.InputBindings>
<DockPanel>
<local:TopMenu DockPanel.Dock="Top" x:Name="TopMenu" />
<ContentControl>
<local:Home x:Name="MainContent" />
</ContentControl>
</DockPanel>
Home.xaml
<UserControl x:Class="SampleWpfApp.Home"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBox HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120" Margin="10,37,0,0"/>
<TextBox HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120" Margin="10,86,0,0"/>
<Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="10,127,0,0"/>
</Grid>
运行应用程序。确保不要单击文本框或文本框的选项卡。单击“文件”菜单。菜单已启用。检查查看帮助菜单。它也已启用。当您单击时,您将看到消息框。一切都很好
但当我点击文本框时,菜单被禁用。在重新启动应用程序并且不单击文本框之前,我无法再次启用菜单。(不过,使用手势仍会触发messagebox)。有人能帮我确定这个问题吗?这让我疯狂了一段时间:(将FocusManager.IsFocusScope=“True”添加到TopMenu用户控件中就成功了。首先,您不需要在
Window2.xaml
和TopMenu.xaml
.ACommandSource
中定义输入绑定(就像按键手势一样)一次定义并添加到RoutedCommand
RoutedCommand
是WPF将命令机制分为四个概念的方法:
命令
是要执行的操作
CommandSource
是调用命令的对象(可以是控件或输入手势)
CommandTarget
是在其上执行命令的对象
CommandBinding
是将命令逻辑映射到命令的对象
RoutedCommands
可以从多个CommandSources
触发,每个CommandSource
可以定义自己的CommandTarget
,树上的每个UIElement
可以通过向RoutedCommand
工作原理:
当CommandSource
触发RoutedCommand
时,一个PreviewExecuted
事件从窗口沿元素树向下挖掘,直到CommandTarget
对象,寻找处理该事件的CommandBinding
如果e.Handled
未设置为True
,则执行的事件将元素树
从CommandTarget
冒泡到窗口
,寻找处理该事件的合适CommandBinding
这里重要的是如何定义CommandTarget
。当未定义CommandSource
的CommandTarget
属性时,具有焦点的控件是默认的CommandTarget
。工具栏和菜单的神奇之处在于它们设置了CommandTarget
性质
他们的子控件指向当前具有焦点的控件。从技术上讲,他们查看父控件,即您案例中的窗口,并在窗口焦点范围中找到最近聚焦的控件,即文本框。工具栏和菜单具有单独的焦点范围
那么您的代码发生了什么:当文本框
具有逻辑焦点时,菜单项
(作为命令源
)将被禁用,但如果您使用定义的键手势
(Ctrl+N和Ctrl+F1),命令将被执行
您已经为每个RoutedCommand
定义了两个CommandSources
:
将CommandTarget
设置为TopMenu的Key手势
。命令
直接查看目标并找到CommandBinding
。这些CommandSources
始终处于启用状态。您按下键,命令就会执行
未设置带有CommandTarget
的MenuItem
。如果窗口中有聚焦控件,则会将其动态设置为聚焦控件。然后我们有两种情况:
- 当
文本框
未聚焦时,不会设置命令目标
。因此命令
会查看窗口
的所有元素
树,并在TopMenu用户控件
中找到命令绑定
。因此TopMenu是命令目标
和命令数据源
已启用
- 当聚焦
Textbox
时,CommandTarget
属性使用该Textbox
进行设置。PreviewCanExecute
和CanExecute
事件在窗口
和文本框
之间通过元素树
进行隧道和冒泡,但它们不会通过TopMenuUserControl
,因为它不是Textbox
的父项。如果未找到任何处理程序,则不会启用命令源
有几种解决方案:
最合乎逻辑的方法是:在Window2
类中定义命令绑定
和事件处理程序
,因为它是最顶层的父类,并且因为您的命令
更像窗口
级别的命令,所以它与UserControlTopMenu
类无关
手动定义MenuItems
的CommandTarget
属性。请参见下文
这就是您所做的,将TopMenu的附加属性FocusManager.IsFocusScope
设置为True
。因此当菜单查看父焦点范围时,它不会查看窗口,而是查看TopMenu
定义MenuItems
的CommandTarget
属性:
<MenuItem Command="New" CommandTarget={Binding RelativeSource=
{RelativeSource AncestorType={x:Type local:TopMenu}}}/>
...
<MenuItem Header="_View Help" InputGestureText="Ctrl+F1"
Command="{x:Static local:TopMenu.ShowHelp}"
CommandTarget={Binding RelativeSource={RelativeSource
AncestorType={x:Type local:TopMenu}}}/>
...
小注释:“ApplicationCommand”是可选的,因为有一个转换器可以找到
<UserControl x:Class="SampleWpfApp.Home"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBox HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120" Margin="10,37,0,0"/>
<TextBox HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120" Margin="10,86,0,0"/>
<Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="10,127,0,0"/>
</Grid>
<MenuItem Command="New" CommandTarget={Binding RelativeSource=
{RelativeSource AncestorType={x:Type local:TopMenu}}}/>
...
<MenuItem Header="_View Help" InputGestureText="Ctrl+F1"
Command="{x:Static local:TopMenu.ShowHelp}"
CommandTarget={Binding RelativeSource={RelativeSource
AncestorType={x:Type local:TopMenu}}}/>