Wpf 从WindowsFormsHost打开时,关联菜单不会响应按键

Wpf 从WindowsFormsHost打开时,关联菜单不会响应按键,wpf,keyboard,contextmenu,windowsformshost,Wpf,Keyboard,Contextmenu,Windowsformshost,当焦点位于WindowsFormsHost中且上下文菜单打开时,上下文菜单不会响应上/下箭头键的按下 以下代码(几乎是独立的)说明了该问题: 这将显示两个文本框,一个WPF和一个WinForms。如果按Ctrl-T键,将出现一个简单的上下文菜单 现在运行程序 将光标放在WPF文本框中 按Ctrl-T键:将显示关联菜单 按向下箭头:选择关联菜单中的第一项(“aaa”) 鉴于 将光标放在WinForms文本框中 按Ctrl-T键:将显示关联菜单 按下向下箭头:什么也没有发生 在我们的应用程序中,键盘

当焦点位于WindowsFormsHost中且上下文菜单打开时,上下文菜单不会响应上/下箭头键的按下

以下代码(几乎是独立的)说明了该问题:

这将显示两个文本框,一个WPF和一个WinForms。如果按Ctrl-T键,将出现一个简单的上下文菜单

现在运行程序

  • 将光标放在WPF文本框中
  • 按Ctrl-T键:将显示关联菜单
  • 按向下箭头:选择关联菜单中的第一项(“aaa”)
  • 鉴于

  • 将光标放在WinForms文本框中
  • 按Ctrl-T键:将显示关联菜单
  • 按下向下箭头:什么也没有发生
  • 在我们的应用程序中,键盘导航是必不可少的,所以这很烦人

    有人能帮我解释一下吗?最好能想出一个解决方案,让第二个案例像第一个一样有效

    (我注意到,普通菜单——至少是用助记符打开的菜单——工作正常)

    更新

    我想,我应该详细介绍一下我正在研究的实际情况:我有一个TabControl,其中每个TabItem的内容都是在其他地方开发的(但通常比较复杂)。我的Ctrl-T上下文菜单将显示选项卡项标题列表,以便在选项卡之间快速导航。(它模仿Visual Studio中选项卡右侧的组合框)

    现在,当当前选项卡的内容是WPF控件且焦点位于该控件内时,一切正常。如果打开关联菜单并选择相同的选项卡,焦点将返回到关联菜单打开前的位置。这是因为上下文菜单是一个焦点范围,所以逻辑焦点保持在控件中的位置

    但是,如果内容是WindowsFormHost,且焦点位于其中,则上下文菜单将无法按上述说明工作。下面的第一个答案通过在打开上下文菜单之前将焦点移动到任何WPF控件来解决这个问题。不幸的是,这也改变了逻辑焦点,使得上下文菜单关闭后无法重置它

    在更改焦点和打开上下文菜单之前,我尝试捕获并保存焦点,但没有成功

    我已经决定的解决办法是只在必要时改变焦点。(签入
    Keyboard.FocusedElement==null
    似乎有效)。这意味着,在WinForms组件中有焦点的情况下,我的解决方案只是次优的,打开上下文菜单并选择不更改选项卡。这是罕见的,所以它比我的第一个问题有了很大的改进


    但我仍然好奇是否存在更好的解决方案。

    我尝试了您的示例应用程序,并注意到当在WPF textBox中使用光标打开contextMenu时,
    逻辑焦点将移动到contextMenu(光标在textBox上不再可见,因此上下文菜单的键工作正常)

    但是,当我尝试使用maskedTextBox时,逻辑焦点停留在textBox上,因此ContextMenu没有可用的键

    因此,作为一种解决方法,我对您的代码进行了调整,看看这是否有帮助-

    <DockPanel Name="DockPanel" Focusable="True" FocusVisualStyle="{x:Null}">
       .....     
    </DockPanel>
    
    更新

    由于其窗口窗体文本框的局限性,它不会将键盘焦点放松在上下文菜单打开上

    因此,我们必须跟踪蒙面文本框在打开前是否有焦点 上下文菜单,然后在上下文菜单打开后手动设置焦点 关闭

    代码示例-

    
    公共主窗口()
    {
    初始化组件();
    InputBindings.Add(
    新密钥绑定(
    新的RelayCommand(OpenContextMenu),
    新的按键手势(Key.T,ModifierKeys.Control));
    msk.GotFocus+=新事件处理程序(msk_GotFocus);
    msk.LostFocus+=新事件处理程序(msk_LostFocus);
    }
    bool是focusonmaskedtextbox;
    void msk_LostFocus(对象发送方,事件参数e)
    {
    isFocusOnMaskedTextBox=false;
    }
    void msk_GotFocus(对象发送方,事件参数e)
    {
    isFocusOnMaskedTextBox=true;
    }
    void OpenContextMenu(对象参数)
    {
    bool moveFocusOnClose=isFocusOnMaskedTextBox;
    RoutedEventHandler eventHandler=null;
    eventHandler=(s,e)=>
    {
    if(moveFocusOnClose)
    msk.Focus();
    DockPanel.ContextMenu.Closed-=eventHandler;
    };
    if(moveFocusOnClose)
    {
    键盘。焦点(DockPanel);
    }
    DockPanel.ContextMenu.IsOpen=true;
    DockPanel.ContextMenu.Closed+=eventHandler;
    }
    
    谢谢你的回答。这一解决方法大大有助于避免问题。然而,这并不完美,因为上下文菜单关闭后焦点将不会返回文本框。我想你必须对此进行修改,有点像我在回答中所做的。因为Winforms控件没有单独的逻辑和键盘焦点。我在示例应用程序中试用过,效果很好。
      public partial class MainWindow : Window
      {
        public MainWindow()
        {
          InitializeComponent();
          InputBindings.Add(
            new KeyBinding(
              new RelayCommand(OpenContextMenu),
              new KeyGesture(Key.T, ModifierKeys.Control)));
        }
    
        void OpenContextMenu()
        {
          DockPanel.ContextMenu.PlacementTarget = DockPanel;
          DockPanel.ContextMenu.Placement = PlacementMode.Center;
          DockPanel.ContextMenu.IsOpen = true;
        }
      }
    
    <DockPanel Name="DockPanel" Focusable="True" FocusVisualStyle="{x:Null}">
       .....     
    </DockPanel>
    
    void OpenContextMenu(object param)
    {
       Keyboard.Focus(DockPanel);
       DockPanel.ContextMenu.PlacementTarget = DockPanel;
       DockPanel.ContextMenu.Placement = PlacementMode.Center;
       DockPanel.ContextMenu.IsOpen = true;
    }
    
    <DockPanel Name="DockPanel" Focusable="True" FocusVisualStyle="{x:Null}">
      <DockPanel.ContextMenu>
         <ContextMenu>
            <MenuItem Header="aaa"/>
            <MenuItem Header="bbb"/>
          </ContextMenu>
       </DockPanel.ContextMenu>
       <StackPanel>
          <TextBox x:Name="txt"/>
          <WindowsFormsHost>
            <wf:MaskedTextBox x:Name="msk"/>
          </WindowsFormsHost>
        </StackPanel>
    </DockPanel>
    
    public MainWindow()
    {
      InitializeComponent();
      InputBindings.Add(
        new KeyBinding(
          new RelayCommand<object>(OpenContextMenu),
            new KeyGesture(Key.T, ModifierKeys.Control)));
       msk.GotFocus += new EventHandler(msk_GotFocus);
       msk.LostFocus += new EventHandler(msk_LostFocus);
    }
    
    bool isFocusOnMaskedTextBox;
    void msk_LostFocus(object sender, EventArgs e)
    {
       isFocusOnMaskedTextBox = false;
    }
    
    void msk_GotFocus(object sender, EventArgs e)
    {
       isFocusOnMaskedTextBox = true;
    }
    
    void OpenContextMenu(object param)
    {
       bool moveFocusOnClose = isFocusOnMaskedTextBox;
       RoutedEventHandler eventHandler = null;
       eventHandler = (s, e) =>
       {
         if (moveFocusOnClose)
            msk.Focus();
         DockPanel.ContextMenu.Closed -= eventHandler;
       };
       if (moveFocusOnClose)
       {
          Keyboard.Focus(DockPanel);
       }
       DockPanel.ContextMenu.IsOpen = true;
       DockPanel.ContextMenu.Closed += eventHandler;
    }