WPF 文本框在 Window 窗体中的 ElementHost 中不接受输入

发布于 2024-07-19 07:15:56 字数 1269 浏览 3 评论 0原文

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

应用程序引擎公开了创建“Dockbar”的能力,它本质上允许您将 Windows 窗体控件放入可以停靠到引擎界面的子窗口内。

我试图将一个简单的 WPF TextBox 放入 ElementHost 控件中,该控件已添加到 Dockbar。 乍一看这似乎工作得很好; 但是在尝试在文本框中键入内容后,实际上只有某些序列出现在文本框中。 删除退格复制粘贴选择文本工作。 如果您输入 AZ、1-9 等,这些键不会显示。

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

我看到一篇讨论 Dispatcher.Run() 的帖子,它可以工作,但破坏了形式的其余部分:

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

PreviewKeyUpPreviewKeyDownKeyUp KeyDown 事件都在 TextBox 上触发,但遗憾的是 TextBox 中没有显示任何文本。

我对 Windows 消息了解不多,但使用 WinSpector 我注意到没有来自 TextBox 的 WM_GETTEXT 消息(我不知道是否应该有)。

我还创建了一个新的 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);

We are developing a UI Control in WPF to be consumed within an existing Windows Forms / MFC application engine (Rhino 3D).

The application engine exposes the ability create a "Dockbar" which essentially lets you put Windows Forms controls inside a child window which can dock to the Engines Interface.

I am attempting to put a simple WPF TextBox inside an ElementHost control, which is added to the Dockbar. This appears to work fine at first glance; but after attempting to type into the TextBox only certain sequences actually show up in the TextBox. The DELETE, BACKSPACE, COPY, PASTE, and SELECTING TEXT work. If you type A-Z, 1-9, etc. those keys do not show up.

I have SCOURED the net, and have heard about the ElementHost.EnableModelessKeyboardInterop() but this only applies to WPF Windows being created from the form. I am only creating WPF UserControls and hosting them in the ElementHost control.

I saw a post which talked about the Dispatcher.Run(), and it sort of works but breaks the rest of the form:

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

The PreviewKeyUp, PreviewKeyDown, KeyUp, and KeyDown events all fire on the TextBox, but alas no text shows up in the TextBox.

I don't know much about Windows Messages, but using WinSpector I noticed that no WM_GETTEXT messages were coming from the TextBox (if they even should be I don't know).

I also create a new Windows Forms project and did the same thing in there and it works fine, so it must be an issue with how the windows are created and docked within the Rhino 3D engine.

Here is the sample code which doesn't work:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

猥琐帝 2024-07-26 07:15:56

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

I finally figured it out after 2 days of head scatching...

The MFC Dialog window was taking the WM_CHAR messages and preventing the control from handling the input. So in order to prevent this, I hook the HwndSource and whenever I receive the WM_GETDLGCODE message I respond back with the types of input to accept, and then mark the event as handled.

I created my own TextBox in order to prevent having to fix every textbox (see Below):

    /// <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;
        }
    }
北斗星光 2024-07-26 07:15:56

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

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

为什么我的 WPF 文本框“有点”只读?

Check out my own question about this very same thing. in the end though, all you need is something like this:

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

Why is my WPF textbox "kinda" readonly?

笑,眼淚并存 2024-07-26 07:15:56

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

I have a similar issue with a wxWidgets parent window and embedded WPF TextBox controls. I found that although attaching ChildHwndSourceHook does solve the problem of not receiving keyboard input, I ended up with occasional duplicate space characters. It seems the WM_KEYDOWN message handles the space characters reliably, but a duplicate WM_CHAR message is also received for some of the spaces. To solve this I added the following clause to the body of the ChildHwndSourceHook function, which simply ignores the WM_CHAR space character:

        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;
        }
远昼 2024-07-26 07:15:56

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

It is not necessary to create derived TextBox. The code for IOTextBox can be used in a UserControl hosting textboxes. I have successfully tested it with WPF control used for custom options page used in VS2010 package.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文