我的示例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: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>
TopMenu.xaml
<UserControl x:Class="SampleWpfApp.TopMenu"
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"
xmlns:local="clr-namespace:SampleWpfApp"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.InputBindings>
<KeyBinding Gesture="CTRL+N" Command="ApplicationCommands.New" />
<KeyBinding Gesture="CTRL+F1" Command="{x:Static local:TopMenu.ShowHelp}" />
</UserControl.InputBindings>
<UserControl.CommandBindings>
<CommandBinding Command="ApplicationCommands.New" Executed="NewExecuted" CanExecute="NewCanExecute"/>
<CommandBinding x:Name="HelpCmdBinding" CanExecute="AltHelpCanExecute" Executed="AltHelpExecuted" Command="{x:Static local:TopMenu.ShowHelp}" />
</UserControl.CommandBindings>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Command="ApplicationCommands.New" />
<MenuItem Header="E_xit" InputGestureText="Alt+F4" />
</MenuItem>
<MenuItem Header="_Help">
<MenuItem Header="_View Help" InputGestureText="Ctrl+F1" Command="{x:Static local:TopMenu.ShowHelp}" />
<MenuItem Header="_About" />
</MenuItem>
</Menu>
</DockPanel>
TopMenu.xaml.cs
public partial class TopMenu : UserControl
{
public static RoutedCommand ShowHelp = new RoutedCommand("AltHelp", typeof(TopMenu));
public TopMenu()
{
InitializeComponent();
}
void NewExecuted(object target, ExecutedRoutedEventArgs e)
{
MessageBox.Show("The " + ((RoutedCommand)e.Command).Name + " command invoked on " + ((FrameworkElement)target).Name);
}
void NewCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
void AltHelpExecuted(object target, ExecutedRoutedEventArgs e)
{
MessageBox.Show("The " + ((RoutedCommand)e.Command).Name + " command invoked on " + ((FrameworkElement)target).Name);
}
void AltHelpCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
}
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>
运行该应用程序。确保不要单击文本框或文本框中的选项卡。单击“文件”菜单。菜单已启用。检查“查看帮助”菜单。它也启用了。单击时,您将看到消息框。一切都很好。
但是当我单击文本框时,菜单被禁用。在重新启动应用程序并且不单击文本框之前,我无法再次启用菜单。 (尽管使用手势仍会触发消息框)。有人可以帮我识别问题吗?这让我疯狂了一段时间:(
答案 0 :(得分:2)
向TopMenu用户控件添加FocusManager.IsFocusScope =“True”就可以了。
答案 1 :(得分:0)
首先,您不需要在Window2.xaml
和TopMenu.xaml
中定义InputBindings。 CommandSource
(如KeyGesture
)已定义并一次性添加到RoutedCommand
。
RoutedCommand
是WPF在四个概念中分离命令机制的方法:
Command
是要执行的操作。CommandSource
是调用命令的对象(可以是Control或InputGesture)。CommandTarget
是正在执行命令的对象。CommandBinding
是将命令逻辑映射到命令的对象。 RoutedCommands
可以从多个CommandSources
触发,每个CommandSource
可以定义自己的CommandTarget
,树上的每个UIElement
都可以实现Executed
通过向CanExecute
添加CommandBinding
来为{}}和RoutedCommand
个事件处理程序。
工作原理:
CommandSource
触发RoutedCommand
时,PreviewExecuted
事件正在element tree
从Window
隧道向CommandTarget
对象挖掘,寻找处理事件的CommandBinding
。e.Handled
未设置为True
,则Executed
事件会将element tree
从CommandTarget
冒泡到Window
,寻找适合处理事件的CommandBinding
。这里重要的是如何定义CommandTarget
。如果未定义CommandTarget
的{{1}}属性,则控件的焦点是默认CommandSource
。 CommandTarget
和Toolbars
的神奇之处在于它们设置了Menu
属性
他们的孩子对目前有重点的控制。从技术上讲,他们会查看父级,在您的情况下为CommandTarget
,并在Window
焦点范围中查找最近关注的控件,即{{1 }}。 Window
和Textbox
有一个单独的焦点范围。
那么您的代码会发生什么:当ToolBar
具有逻辑焦点时,Menu
(作为Textbox
)被禁用,但如果您使用定义的MenuItems
(Ctrl + N和Ctrl + F1)执行命令。
您为每个CommandSource
定义了两个KeyGesture
:
CommandSources
RoutedCommand
设置为TopMenu。 KeyGesture
会直接查看目标并找到CommandTarget
。那些Command
总是被启用。你按下键并执行命令。未设置CommandBinding
的{{1}}。如果CommandSources
焦点范围中有一个,则动态设置为焦点控制。然后我们有两个场景:
MenuItem
,则不会设置CommandTarget
。因此,Window
会查看Textbox
的所有CommandTarget
树,并在TopMenu Command
中找到element
。因此,TopMenu是Window
,而CommandBinding
已启用。UserControl
时,CommandTarget
属性设置为此CommandSource
。 Textbox
和CommandTarget
事件正在Textbox
和PreviewCanExecute
之间CanExecute
进行隧道挖掘和冒泡,但他们不会通过TopMenu element tree
,因为它不是Window
的父级。找不到处理程序,然后Textbox
未启用。有几种解决方案:
UserControl
课程中的Textbox
和CommandSource
,因为它是最顶级的父级,因为您的CommandBindings
是event handlers
更像是Window2
级命令,它与UserControl Commands
类无关。Window
的{{1}}属性。见下文。TopMenu
设置为CommandTarget
。因此,当MenuItems
查看父焦点范围时,它不会查看FocusManager.IsFocusSope
,它会查看TopMenu。定义True
的{{1}}属性:
Menu
小评:&#34; ApplicationCommands&#34;是可选的,因为有一个转换器找到了正确的Window
。
当您需要多个CommandTarget
为同一命令定义不同的逻辑时,了解WPF命令机制是很好的。每个MenuItems
都可以按照自己需要的方式在本身上执行<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}}}/>
。