WPF TextBox在Window窗体中的ElementHost中不接受输入

时间:2009-05-07 17:02:16

标签: wpf interop textbox elementhost

我们正在开发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);

4 个答案:

答案 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();

Why is my WPF textbox "kinda" readonly?

答案 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包中使用的自定义选项页面。