我们正在开发WPF中的UI控件,以便在现有的Windows窗体/ MFC应用程序引擎(Rhino 3D)中使用。
应用程序引擎公开了创建“Dockbar”的能力,它实质上允许您将Windows窗体控件放在可以停靠到引擎接口的子窗口中。
我试图将一个简单的WPF TextBox放在ElementHost控件中,该控件被添加到Dockbar中。乍一看似乎工作得很好;但在尝试输入TextBox后,只有某些序列实际显示在TextBox中。 DELETE , BACKSPACE , COPY , PASTE 和选择文字可以正常工作。如果您键入A-Z,1-9等,则这些键不会显示。
我已经浏览了网络,并且听说过 ElementHost.EnableModelessKeyboardInterop()
,但这仅适用于从表单创建的WPF Windows。我只创建WPF UserControl并将它们托管在ElementHost控件中。
我看到一篇关于Dispatcher.Run()的帖子,它有点工作但是打破了表单的其余部分:
System.Windows.Threading.Dispatcher.Run();
PreviewKeyUp , PreviewKeyDown , KeyUp 和 KeyDown 事件全部在TextBox上触发,但是没有文本显示在TextBox中。
我对Windows消息了解不多,但是使用WinSpector我发现没有WM_GETTEXT消息来自TextBox(如果它们甚至应该是我不知道的话)。
我还创建了一个新的Windows窗体项目并在那里做了同样的事情并且工作正常,因此它必须是如何在Rhino 3D引擎中创建和停靠窗口的问题。
以下是不起作用的示例代码:
ElementHost el = new ElementHost();
System.Windows.Controls.TextBox t = new System.Windows.Controls.TextBox();
t.Width = 100;
t.Text = "TEST";
el.Child = t;
panel1.Controls.Add(el);
答案 0 :(得分:21)
我终于在头部散射2天后想出来了......
“MFC对话框”窗口正在显示 WM_CHAR
消息,并阻止控件处理输入。因此,为了防止这种情况,我挂钩了HwndSource,每当收到 WM_GETDLGCODE
消息时,我都会回复接受的输入类型,然后将事件标记为已处理。
我创建了自己的TextBox,以防止必须修复每个文本框(参见下文):
/// <summary>
/// Interop Enabled TextBox : This TextBox will properly handle WM_GETDLGCODE Messages allowing Key Input
/// </summary>
class IOTextBox : TextBox
{
private const UInt32 DLGC_WANTARROWS = 0x0001;
private const UInt32 DLGC_WANTTAB = 0x0002;
private const UInt32 DLGC_WANTALLKEYS = 0x0004;
private const UInt32 DLGC_HASSETSEL = 0x0008;
private const UInt32 DLGC_WANTCHARS = 0x0080;
private const UInt32 WM_GETDLGCODE = 0x0087;
public IOTextBox() : base()
{
Loaded += delegate
{
HwndSource s = HwndSource.FromVisual(this) as HwndSource;
if (s != null)
s.AddHook(new HwndSourceHook(ChildHwndSourceHook));
};
}
IntPtr ChildHwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_GETDLGCODE)
{
handled = true;
return new IntPtr(DLGC_WANTCHARS | DLGC_WANTARROWS | DLGC_HASSETSEL);
}
return IntPtr.Zero;
}
}
答案 1 :(得分:10)
查看我自己关于同样事情的问题。最后,你需要的只是这样:
Window window1 = new Window();
ElementHost.EnableModelessKeyboardInterop(window1);
window1.Show();
答案 2 :(得分:6)
我在wxWidgets父窗口和嵌入式WPF TextBox控件方面遇到了类似的问题。我发现虽然附加ChildHwndSourceHook确实解决了没有接收键盘输入的问题,但我最终偶尔会出现重复的空格字符。似乎WM_KEYDOWN消息可靠地处理空格字符,但是对于某些空格也接收到重复的WM_CHAR消息。为了解决这个问题,我在ChildHwndSourceHook函数的主体中添加了以下子句,它只是忽略了WM_CHAR空格字符:
const UInt32 WM_CHAR = 0x0102;
if (msg == WM_CHAR)
{
// avoid duplicated spaces when parent window is a native window
if (wParam.ToInt32() == 32)
handled = true;
}
答案 3 :(得分:6)
没有必要创建派生的TextBox。 IOTextBox的代码可以在UserControl托管文本框中使用。我已成功使用WPF控件对其进行测试,该控件用于VS2010包中使用的自定义选项页面。