14

WindowsFormsHostとタブナビゲーション内でWinFormsフォームをホストするときに問題が発生しました。解決するために、私はこの簡単な例を作成しました:

  • 作成されたWPF Window(アプリの開始点)
  • Form2つのWinFormを作成TextBoxしました
  • WPFウィンドウ:追加WindowsFormsHostされました
  • WPFウィンドウ:OnLoadedハンドラーを追加
  • WPFウィンドウ:Textbox下に配置を追加WindowsFormsHost

私が得たOnLoadedハンドラーで:

System.Windows.Forms.Form f = new WinFormsForm();
f.TopLevel = false;
f.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.windowsFormsHost1.Child = f;

アプリケーションを実行すると、次のようになります。

  • 何も焦点を当てていません(ok)
  • TextBoxの最初をクリックすると、WindowsFormsHostフォーカスが移動します(ok)
  • タブを押すと、フォーカスが(ok)TextBoxの2番目に移動しますWindowsFormsHost
  • もう一度Tabキーを押すと、フォーカスが1番目に戻りますTextBoxWindowsFormsHostOKではありませんWindowsFormsHost。WPFウィンドウの下部にあるテキストボックスにフォーカスを置いたままにしておく必要があります)
  • wpf(の前後に配置WindowsFormsHost)のテキストボックスをクリックすると、フォーカスが取得されます(ok)
  • タブを押すと、フォーカスがの最初のテキストボックスにWindowsFormsHost移動します。終了後に最初に移動するはずです。だからこれも大丈夫です
  • wpfテキストボックスをもう一度クリックしてShift+Tabキーを押すと、フォーカスがWindowsFormsHost(ok)の2番目のテキストボックスに移動します。
  • Tabキーを押すと、フォーカスがWindowsFormsHost(WFHで始まる)の最初のテキストボックスに移動します(OKではありません)

1つのタイプのコントロールしかない場合のようにフォーカスを動作させるにはどうすればよいですか?この場合、WFH-1st-Textbox、WFH-2nd-Textbox、WPF-Textboxのタブ順序を意味します。

4

4 に答える 4

7

私が見つけた記事によると、それは達成できないようです。MSDNブログエントリ(セクションHwnds)によると、Windowsフォームコントロールは常に階層内のWPFコントロールの上にあります。MSDNの記事(「WPFメッセージループからのメッセージの取得」セクション)には、WindowsFormsHost要素で発生するイベントは、WPFがそれらを認識する前に処理されると記載されています。

したがって、Tabキーを押して発生したイベントは、WindowsFormsHost要素によって処理されると想定しています(結果として、他のテキストボックスがフォーカスされます)。囲んでいるWPFウィンドウでは、「既に処理されている」ため、イベントが発生することはありません。一方、WPFテキストボックスのTabキーを押すと、WPFがイベント自体を処理し、コントロールチェーンが正常に処理されます。これにより、フォーカスはWindowsFormsHost要素のテキストボックスに移動し、そこからキーボードを使用してテキストボックスを離れることはできません。

私はこれがあなたの現在の問題を助けないことを知っていますが、それがいくつかのことを説明することを願っています。


補遺 フォームコントロールの使用に依存していない場合は、同じコントロール要素を含むWinFormsユーザーコントロールに変更できます。その後、次の方法でWindowsFormsHost要素の初期化を変更します。

System.Windows.Forms.UserControl control = new WinFormUC();
windowsFormsHost1.Child = control;

WinFormUCクラスは、前述のテキストボックスを含む私のWinFormsユーザーコントロールです。私のテストでは、Tabキーを押すと、WinformsテキストボックスかWPFテキストボックスかに関係なく、テキストボックスが次々にフォーカスされていました。

于 2011-05-13T23:29:00.580 に答える
4

あなたは少しのトリックでこれを行うことができます。ホストを含​​むwpfフォームが次のようになっているとします。

<StackPanel>
    <TextBox LostFocus="TextBox_LostFocus" />
    <wf:WindowsFormsHost Name="host" />
    <TextBox/>
</StackPanel>

最初のテキストボックスのLostFocusイベントで、WinFormの最初のボタンにフォーカスを設定します。このようにして、フォーカスが常に最初のボタンから始まることを保証します。

private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
    Form1 f = (Form1)host.Child;
    f.EnableTabStops(true);
}

WinFormでは、EnableTabStopsを次のようにコーディングする必要があります。

public void EnableTabStops(bool IsEnabled)
{
    this.button1.TabStop = IsEnabled;
    this.button2.TabStop = IsEnabled;
    if (IsEnabled) button1.Focus();
}

次に、winformのボタンをタブで移動します。winformの最後のボタンを入力したら、すべてのタブストップを無効化/削除して、次のタブがその親のwpfフォームにのみジャンプできるようにします。

private void button2_Enter(object sender, EventArgs e)
{
    EnableTabStops(false);
}

これでうまくいくはずです。

于 2011-05-14T12:02:56.810 に答える
4

これは私がこれを実装した方法です:

WindowsFormsHostから継承するコントロールを作成しました

public class MyWpfControl: WindowsFormsHost
{
    private MyWindowsFormsControl _winControl = new MyWindowsFormsControl ();

    public MyWpfControl()
    {
        _winControl.KeyDown += _winControl_KeyDown;
    }

    void _winControl_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Tab && e.Shift)
        {
            MoveFocus(new TraversalRequest(FocusNavigationDirection.Previous));                          
        }
        else if (e.KeyCode == Keys.Tab)
        {
            MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));              
        }                 
    } 
}

私のために完璧に働いた

同じアプローチを使用して、Windowsコントロールに必要なwpfデータバインディングを持たせることもできます。

public static readonly RoutedEvent SelectionChangedEvent =    EventManager.RegisterRoutedEvent("SelectionChanged", RoutingStrategy.Bubble,  typeof(RoutedEventHandler), typeof(MyWpfControl));

    public event RoutedEventHandler SelectionChanged
    {
        add { AddHandler(SelectionChangedEvent, value); }
        remove { RemoveHandler(SelectionChangedEvent, value); }
    }

    void RaiseSelectionChangedEvent()
    {
        var newEventArgs = new RoutedEventArgs(SelectionChangedEvent);
        RaiseEvent(newEventArgs);
    }

    private void InitDependencyProperties()
    {
        _winControl.EditValueChanged += (sender, e) =>
        {
            SetValue(SelectedValueProperty, _winControl.EditValue);

            if (!_disabledSelectionChangedEvent)
            {
                RaiseSelectionChangedEvent();
            }
        };

    }

public static readonly DependencyProperty SelectedValueProperty = DependencyProperty.Register("SelectedValue", typeof(string), typeof(MyWpfControl),
   new PropertyMetadata("",
     (d, e) =>
     {
         var myControl = d as MyWpfControl;
         if (myControl != null && myControl._brokersCombo != null)
         {
             var val = myControl.GetValue(e.Property) ?? string.Empty; 
             myControl._winControl.EditValue = val;                              
         }
     }, null));

XAMLは次のとおりです。

<u:MyWpfControl x:Name="myWpfControl" Margin="5,0,0,0" DataSource="{Binding BindingData,     UpdateSourceTrigger=PropertyChanged}" SelectedValue="{Binding SelectedPropertyNameOnViewModel, Mode=TwoWay}">
</u:MyWpfControl>
于 2013-11-24T16:48:59.003 に答える
1

App.xaml.csに追加するだけです:

System.Windows.Forms.Integration.WindowsFormsHost.EnableWindowsFormsInterop();

参照:WindowsFormsIntegration.dll

于 2018-09-12T08:09:28.750 に答える