需要能够退出Alt键下划线模式,可能使用ESC键

时间:2013-07-09 13:14:10

标签: wpf keyboard-shortcuts

问题:按下并释放Alt键后如何退出键盘热键模式?在Office中,ESC可以正常工作,但在WPF中却没有。

详情:我在WPF应用程序中有各种Label个元素。

<StackPanel>
    <Label Grid.Column="0" VerticalAlignment="Center" Content="_Textbox 1" Target="textbox1" />
    <TextBox x:Name="textbox1" Width="50" />
    <Label Grid.Column="0" VerticalAlignment="Center" Content="T_extbox 2" Target="textbox2" />
    <TextBox x:Name="textbox2" Width="50" />
</StackPanel>

当我按下并释放Alt键时,P会加下划线,然后我可以单独按下P键,然后该标签就会采取行动。这与Word 2013和Notepad的工作原理相同,因为您无需同时按下AltP

WPF不同的地方是我无法按ESC键来停止下划线并停止自动导航到Label控件。我看到退出键盘导航模式的唯一方法是使用鼠标并单击某处,从而击败键盘导航的目标。

1 个答案:

答案 0 :(得分:0)

添加到我原来的评论

  

实际上,Notepad和Word 2013的行为略有不同。使用热键的控件位于菜单中,只要按下Alt键即可获得焦点,您可以看到它们得到的焦点是文本区域插入符缺失,Esc然后在清除“_”时将焦点返回到TextBox。现在在示例代码中,如果您将两个Label或甚至一个放在一个,然后按Alt,您将获得与Word或记事本相同的行为。没有菜单,就没有想要进行中间焦点的控制。

这似乎是一个问题,Menu获得延迟焦点来处理它自己的FocusManager.IsFocusScope中的这些热键。

MSDN的另一个片段:

  

以下方案说明了Windows Presentation Foundation(WPF)应用程序中键盘焦点和逻辑焦点的更改方式,该应用程序具有带TextBox的窗口和具有MenuItem的Menu。当键盘焦点从TextBox更改为MenuItem时,TextBox会丢失键盘焦点,但会保留Window焦点范围的逻辑焦点。 MenuItem获得键盘焦点并获得Menu焦点范围的逻辑焦点。当键盘焦点返回到根窗口时,具有逻辑焦点的Window焦点范围中的元素将获得键盘焦点,在本例中为TextBox。 TextBox现在具有键盘焦点和逻辑焦点。 MenuItem失去了键盘焦点,但保留了菜单焦点范围的逻辑焦点。

<强>解决方案:

如果您无法忍受Menu强加的分组要求以实现热键功能的事实,您可以执行以下操作:

<Grid Margin="25">
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="15" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="*" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" />
    <ColumnDefinition Width="*" />
    <ColumnDefinition Width="*" />
  </Grid.ColumnDefinitions>
  <!-- cannot use Visibility="Collapsed" or "Hidden" on the Menu to make it take focus on Alt press --> 
  <Menu Width="0"
        Height="0">
    <Label x:Name="label1"
            Content="_Textbox 1"
            Target="{Binding ElementName=textbox1}" />
    <Label x:Name="label2"
            Content="T_extbox 2"
            Target="{Binding ElementName=textbox2}" />
    <Label x:Name="label3"
            Content="Another Loose Label to Link Text_Box 1"
            Target="{Binding ElementName=textbox1}" />
  </Menu>
  <Label Grid.Row="0"
          Grid.Column="0"
          Content="{Binding ElementName=label1,
                            Path=Content}" />
  <TextBox x:Name="textbox1"
            Grid.Row="0"
            Grid.Column="1"
            Grid.ColumnSpan="2"
            Margin="15 0 0 0"
            VerticalAlignment="Center" />
  <Label Grid.Row="2"
          Grid.Column="0"
          Content="{Binding ElementName=label2,
                            Path=Content}" />
  <TextBox x:Name="textbox2"
            Grid.Row="2"
            Grid.Column="1"
            Grid.ColumnSpan="2"
            Margin="15 0 0 0"
            VerticalAlignment="Center" />
  <Rectangle Grid.Row="3"
              Grid.RowSpan="2"
              Grid.Column="1"
              Margin="10"
              Fill="Tomato" />
  <Label Grid.Row="4"
          Grid.Column="2"
          Content="{Binding ElementName=label3,
                            Path=Content}" />
</Grid>

因此,在此设置中,我们不会对任何控件使用任何自定义Style。我们几乎创建了一个新的顶级Menu并将所有想要的热键Label添加到其中,并将其宽度和高度设置为0.

因此,在实际的Visible Grid布局中,我们可以将可见的Label置于我们选择的位置,并避免代码重复,为每个Label.Content指定Label两次(一旦进入菜单,然后在实际布局中,我们使用Binding从菜单中的相应标签获取可视标签的内容。

<强>更新

回复OP的评论:

  

我不确定这在我的申请中是否实用。我在整个应用程序中都有热键,其中一些是屏幕间重复的。实现这种类型的解决方法是不可维护的。

好吧,我没有看到重复或有什么东西对这个tbh产生任何影响。

  • 如果您在多个Window中有重复的热键,请将这些重复项目的Content定义为xaml中的String资源,或者您的.resx可以引用它无处不在。
  • 可维护 - 嗯,你没有任何特殊的可维护性。您的布局不受影响,您不受任何限制。如果您有<Menu>个隐藏在每个Window的顶级隐藏的Window隐藏在Window并且在该窗口内的任何控件都需要该功能绑定到相应的Menu子项。我认为它将Label中的热键范围统一到一个地方而不是多个不同的地方。

最后,我并没有试图将这种方法强加给你,这可以归结为你个人的偏好。如果您对它感到不舒服,那么您可以获得{{1}}的子类并自行实现延迟焦点的功能,或者引发Microsoft错误,看看他们是否可以为您解决或找到替代解决方案或让全力以赴的热门功能。