在窗口窗体的ElementHost中时,WPF文本框不接受输入 [英] WPF TextBox not accepting Input when in ElementHost in Window Forms

查看:213
本文介绍了在窗口窗体的ElementHost中时,WPF文本框不接受输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

应用程序引擎公开了创建停靠栏"的功能,该功能实际上使您可以将Windows Forms控件放在可以停靠到引擎界面的子窗口中.

我试图将一个简单的WPF文本框放入ElementHost控件中,该控件已添加到Dockbar中.乍一看似乎很好.但在尝试输入文本框后,只有某些序列实际显示在文本框中. 删除后退复制粘贴选择文本.如果您键入A-Z,1-9等,这些键将不会显示.

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

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

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

PreviewKeyUp PreviewKeyDown KeyUp KeyDown 事件均会在TextBox上触发,但是可惜没有文本显示在文本框中.

我对Windows消息了解不多,但是使用WinSpector时,我注意到没有WM_GETTEXT消息来自文本框(即使我不知道).

我还创建了一个新的Windows Forms项目,并在那里执行了同样的操作,并且效果很好,因此,如何在Rhino 3D引擎中创建和停靠Windows一定是一个问题.

这是无效的示例代码:

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

解决方案

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

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

解决方案

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

这篇关于在窗口窗体的ElementHost中时,WPF文本框不接受输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆