在WindowsFormsHost
和标签导航中托管WinForms表单时遇到了问题。要解决我已经做了这个简单的例子:
Window
(应用的起点)Form
的WinForms TextBox
WindowsFormsHost
OnLoaded
处理程序Textbox
WindowsFormsHost
在我得到的OnLoaded
处理程序中:
System.Windows.Forms.Form f = new WinFormsForm();
f.TopLevel = false;
f.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.windowsFormsHost1.Child = f;
当我现在运行应用程序时:
TextBox
中的第一个WindowsFormsHost
,它得到了关注(确定)TextBox
中的第二个WindowsFormsHost
(确定)TextBox
中的第WindowsFormsHost
位(不确定;应该离开WindowsFormsHost
并将焦点放在文本框中在WPF窗口的底部)WindowsFormsHost
之后和之下),它得到了焦点(确定)WindowsFormsHost
中的第一个文本框 - 因为它应该在结束后开始。所以这也没关系WindowsFormsHost
中的第二个文本框(ok)WindowsFormsHost
中的第一个文本框(以WFH开头)(不确定)如果我只有一种类型的控件,我如何使焦点行为?这意味着WFH-1st-Textbox,WFH-2nd-Textbox,WPF-Textbox的Tab键顺序。
答案 0 :(得分:7)
根据我发现的文章,这似乎无法实现。根据{{3}}(Hwnds部分),Windows窗体控件始终位于层次结构中的WPF控件之上。 MSDN Blog Entry(从WPF消息循环获取消息部分)指出,在WPF甚至意识到它们之前,将处理WindowsFormsHost元素中发生的事件。
所以我假设通过按TAB键触发的事件由WindowsFormsHost元素处理(导致其他文本框的焦点)。在封闭的WPF窗口中,永远不会遇到该事件,因为“它已被处理”。另一方面,当您按下WPF文本框中的TAB键时,WPF正在处理事件本身并正常处理控制链。有了这个,焦点将转到WindowsFormsHost元素中的文本框,从那里你不能使用键盘离开它。
我知道这对你当前的问题没有帮助,但我希望它能解释一些事情。
<强>附录强> 如果您不依赖于使用表单控件,则可以将其更改为WinForms用户控件,其中包含相同的控件元素。之后,您可以通过以下方式更改WindowsFormsHost元素的初始化:
System.Windows.Forms.UserControl control = new WinFormUC();
windowsFormsHost1.Child = control;
类WinFormUC是我的WinForms用户控件,包含上面提到的文本框。在我的测试中,无论是Winforms还是WPF文本框,按下TAB键都会逐个聚焦文本框。
答案 1 :(得分: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上的最后一个按钮后,您禁用/删除所有tabstops,以便下一个选项卡只能跳转到其父wpf表单,如下所示:
private void button2_Enter(object sender, EventArgs e)
{
EnableTabStops(false);
}
这应该可以胜任。
答案 2 :(得分: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>
答案 3 :(得分:1)
只需在App.xaml.cs中添加它即可:
System.Windows.Forms.Integration.WindowsFormsHost.EnableWindowsFormsInterop();
参考:WindowsFormsIntegration.dll