14

WindowsFormsHost在 a和选项卡导航中托管 WinForms 表单时遇到问题。为了解决我做了这个简单的例子:

  • 创建 WPF Window(应用程序的起点)
  • Form创建了带有两个TextBox的WinForms
  • 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;

当我现在运行应用程序时:

  • 没有重点(好的)
  • 我点击第一个TextBoxWindowsFormsHost它得到焦点(好的)
  • 我按 Tab,焦点转到(确定)TextBox中的第二个WindowsFormsHost
  • 我再次按 Tab,焦点回到第TextBox一个WindowsFormsHost不好;应该离开WindowsFormsHost并将焦点放在 WPF 窗口底部的文本框)
  • 我单击 wpf 中的文本框(位于 之后和之下WindowsFormsHost),它获得焦点(好的)
  • 我按下制表符,焦点转到第一个文本框WindowsFormsHost- 因为它应该在结束后开始。所以这也可以
  • 我再次单击 wpf 文本框并按 shift+tab,焦点转到WindowsFormsHost(确定)中的第二个文本框
  • 我按 Tab,焦点转到第一个文本框WindowsFormsHost(转到 WFH 开头)(不好

如果我只有一种类型的控件,如何使焦点表现得像?在这种情况下,表示 WFH-1st-Textbox、WFH-2nd-Textbox、WPF-Textbox 的 Tab 键顺序。

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 用户控件,包含上述文本框。在我的测试中,无论是 Winforms 还是 WPF 文本框,按 TAB 键一个接一个地聚焦文本框。

于 2011-05-13T23:29:00.580 回答
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 回答
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 回答
1

只需将其添加到 App.xaml.cs 中:

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

参考:WindowsFormsIntegration.dll

于 2018-09-12T08:09:28.750 回答