1

フォーカスが WindowsFormsHost にあり、コンテキスト メニューが開いている場合、コンテキスト メニューは上下の矢印キーを押しても反応しません。

この問題は、次の (ほぼ自己完結型の) コードで示されています。

<Window x:Class="FocusAndWinformsSimple.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
        Title="MainWindow" Height="350" Width="525">
  <DockPanel Name="DockPanel">
    <DockPanel.ContextMenu>
      <ContextMenu>
        <MenuItem Header="aaa"/>
        <MenuItem Header="bbb"/>
      </ContextMenu>
    </DockPanel.ContextMenu>
    <StackPanel>
      <TextBox/>
      <WindowsFormsHost>
        <wf:MaskedTextBox/>
      </WindowsFormsHost>
    </StackPanel>
  </DockPanel>
</Window>

コードビハインド:

  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;
    }
  }

これにより、WPF と WinForms の 2 つのテキスト ボックスが表示されます。Ctrl-T を押すと、簡単なコンテキスト メニューが表示されます。

プログラムを実行します

  1. カーソルを WPF テキスト ボックスに置きます
  2. Ctrl-T を押します: コンテキスト メニューが表示されます
  3. 下矢印キーを押す: コンテキスト メニューの最初の項目 ('aaa') が選択されます。

一方

  1. WinForms テキスト ボックスにカーソルを置きます。
  2. Ctrl-T を押します: コンテキスト メニューが表示されます
  3. 下矢印を押す: 何も起こらない

私たちのアプリケーションでは、キーボード ナビゲーションが不可欠なので、これは非常に面倒です。

説明を手伝ってくれる人はいますか?そして、できれば解決策を見つけて、2番目のケースを最初のケースとして機能させます。

(少なくともニーモニックを使用して開いた通常のメニューは正常に機能することに気付きました)。

アップデート

私が取り組んでいる実際のケースについて少し詳しく説明する必要があると思います。各 TabItem のコンテンツが別の場所で開発されている (しかし通常は複雑な) TabControl があります。私の Ctrl-T コンテキスト メニューには、タブ間をすばやく移動できるようにタブ項目のタイトルのリストが表示されます。(Visual Studio のタブの右側にあるコンボボックスを模倣しています)。

現在、現在のタブのコンテンツが WPF コントロールであり、フォーカスがコントロール内にある場合、すべて正常に動作します。コンテキスト メニューを開いて同じタブを選択すると、コンテキスト メニューが開く前の場所にフォーカスが戻ります。これは、コンテキスト メニューがフォーカス スコープであるため機能するため、論理フォーカスはコントロール内にあった場所に残ります。

ただし、コンテンツが WindowsFormHost であり、フォーカスが内部にある場合、コンテキスト メニューは上記のように機能しません。以下の最初の回答では、コンテキスト メニューを開く前にフォーカスを任意の WPF コントロールに移動することでこれを修正しています。残念ながら、これにより論理フォーカスも変更され、コンテキスト メニューを閉じた後にリセットできなくなります。

フォーカスを変更してコンテキストメニューを開く前に、フォーカスをキャプチャして保存しようとしましたが、うまくいきませんでした。

私が落ち着いた解決策は、必要な場合にのみフォーカスを変更することです。(のチェックインは機能してKeyboard.FocusedElement == nullいるようです)。これは、WinForms コンポーネントにフォーカスがあり、コンテキスト メニューを開き、タブを変更しないことを選択した場合にのみ、私のソリューションが最適ではないことを意味します。これはめったにないので、最初の問題よりも大幅に改善されています。

しかし、より良い解決策が存在するかどうかを知りたいと思っています。

4

1 に答える 1

0

私はあなたのサンプルアプリを試してみました.contextMenuがWPF textBoxのカーソルで開かれている場合、contextMenuにlogical focus移動することに気付きました.

ただし、maskedTextBox で試してみると、論理フォーカスは textBox にとどまるため、ContextMenu で機能するキーはありません。

回避策として、コードを微調整しました。これが役立つかどうかを確認してください-

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

FocusableDockPanel を true およびnull に設定FocusVisualStyleして、フォーカスを取得したときに DockPanel の周りの点線を削除します。

そして、contextMenu を開く前に、論理フォーカスを手動でその PlacementTarget、つまり DockPanel に次のように置きます -

void OpenContextMenu(object param)
{
   Keyboard.Focus(DockPanel);
   DockPanel.ContextMenu.PlacementTarget = DockPanel;
   DockPanel.ContextMenu.Placement = PlacementMode.Center;
   DockPanel.ContextMenu.IsOpen = true;
}

アップデート

ウィンドウ フォーム textBox の制限により、コンテキスト メニューを開く際にキーボード フォーカスが失われません。

そのため、コンテキスト メニューを開く前にマスクされた textBox にフォーカスがあったかどうかを追跡し、コンテキスト メニューを閉じたら手動でフォーカスを設定する必要があります。

コードサンプル -

<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;
}
于 2012-08-15T09:08:19.637 に答える