【问题标题】:WPF TextBox not accepting Input when in ElementHost in Window Forms在窗口窗体中的 ElementHost 中时 WPF 文本框不接受输入
【发布时间】:2009-05-07 17:02:16
【问题描述】:

我们正在 WPF 中开发一个 UI 控件,以便在现有的 Windows 窗体/MFC 应用程序引擎 (Rhino 3D) 中使用。

应用程序引擎公开了创建“Dockbar”的能力,这实际上让您可以将 Windows 窗体控件放在可以停靠到引擎界面的子窗口中。

我正在尝试将一个简单的 WPF 文本框放入 ElementHost 控件中,该控件已添加到 Dockbar。乍一看,这似乎工作正常;但在尝试输入文本框后,只有某些序列实际显示在文本框中。 DELETEBACKSPACECOPYPASTESELECTING TEXT 工作。如果您键入 A-Z、1-9 等,这些键不会显示。

我已经在网上搜索过,并且听说过 ElementHost.EnableModelessKeyboardInterop() 但这仅适用于从表单创建的 WPF Windows。我只是创建 WPF 用户控件并将它们托管在 ElementHost 控件中。

我看到一篇关于 Dispatcher.Run() 的帖子,它有点工作,但破坏了表单的其余部分:

System.Windows.Threading.Dispatcher.Run();

PreviewKeyUpPreviewKeyDownKeyUpKeyDown 事件都会在 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);

【问题讨论】:

    标签: wpf interop textbox elementhost


    【解决方案1】:

    抓了2天终于搞明白了……

    MFC 对话窗口接收 WM_CHAR 消息并阻止控件处理输入。因此,为了防止这种情况发生,我挂钩 HwndSource,每当我收到 WM_GETDLGCODE 消息时,我都会回复要接受的输入类型,然后将事件标记为已处理。

    我创建了自己的文本框,以避免修复每个文本框(见下文):

        /// <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;
            }
        }
    

    【讨论】:

    • 谢谢,这正是我所需要的。我把它放在 UserControl 中,就像下面建议的 IvanH 一样。像魅力一样工作!
    • 谢谢!今天我们遇到了这个问题,很快就解决了!
    【解决方案2】:

    查看我自己关于这件事的问题。最后,你所需要的只是这样的:

    Window window1 = new Window();
    ElementHost.EnableModelessKeyboardInterop(window1);
    window1.Show();
    

    Why is my WPF textbox "kinda" readonly?

    【讨论】:

    • 其实在我的问题中我说你的解决方案不适用,我不是窗口,我是 ElementHost 中的 UserControl,在 MFC 对话框窗口中...
    • 你对,我的错。没有密切关注是我应得的。
    • @Russ 这个答案对我帮助很大!!!我花了数周时间试图解决这个问题。谢谢!!!
    • @scartag 很高兴为您提供帮助!我知道有时甚至以有用的方式提出问题是多么困难。并花了几天时间寻找简单的东西。
    【解决方案3】:

    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;
            }
    

    【讨论】:

    • 伙计,经过 1 天的调试,你救了我的命……我的 Enter 键也有类似的问题,有时会发送两次。 WM_KEYDOWN - WM_CHAR - WM_KEYUP,这是顺序。 “Eating” WM_CHAR for Enter 外观不会导致任何问题,除了修复加倍问题。
    【解决方案4】:

    不必创建派生文本框。 IOTextBox 的代码可用于承载文本框的 UserControl。我已经使用用于 VS2010 包中使用的自定义选项页面的 WPF 控件成功对其进行了测试。

    【讨论】:

    • 您能解释一下如何使用Iotextbox吗?
    • @RajeshSubramanian:6 年后我有点难以回答这个问题,但我尝试了一下。整个问题是关于 ElementHost 控件中使用的TextBoxes 的相当具体的问题。 Jason Stevenson answer 中的 IOTextBox 是派生的 TextBox 用于解决问题。我的回答说创建派生控件不是必需的,并且可以在控件容器中处理事件(更轻量级但封装更少)。
    • 非常感谢。我面临同样的问题。我想知道是否存在任何简单的解决方案。
    猜你喜欢
    • 2012-05-12
    • 2012-11-23
    • 1970-01-01
    • 1970-01-01
    • 2018-10-23
    • 1970-01-01
    • 1970-01-01
    • 2012-05-31
    • 1970-01-01
    相关资源
    最近更新 更多