WPF TextBox не принимает входные данные в ElementHost в формах окон - PullRequest
20 голосов
/ 07 мая 2009

Мы разрабатываем элемент управления пользовательского интерфейса в WPF для использования в существующем ядре приложений Windows Forms / MFC (Rhino 3D).

Движок приложения предоставляет возможность создания «панели Dock», которая, по сути, позволяет помещать элементы управления Windows Forms в дочернее окно, которое может пристыковываться к интерфейсу Engines.

Я пытаюсь поместить простой текстовый блок WPF в элемент управления ElementHost, который добавляется на панель Dockbar. На первый взгляд это работает нормально; но после попытки ввода в TextBox в TextBox действительно отображаются только определенные последовательности. DELETE , BACKSPACE , COPY , PASTE и ВЫБОР ТЕКСТА . Если вы вводите A-Z, 1-9 и т. Д., Эти клавиши не отображаются.

Я НАЧАЛ сеть и слышал о ElementHost.EnableModelessKeyboardInterop(), но это относится только к Windows WPF, создаваемой из формы. Я только создаю пользовательские элементы управления WPF и размещаю их в элементе управления ElementHost.

Я видел пост, в котором говорилось о Dispatcher.Run (), и он вроде работает, но ломает остальную часть формы:

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

События PreviewKeyUp , PreviewKeyDown , KeyUp и KeyDown происходят все в TextBox, но, увы, никакой текст не отображается в TextBox.

Я не очень разбираюсь в сообщениях Windows, но, используя WinSpector, я заметил, что из TextBox не приходят сообщения WM_GETTEXT (если они вообще должны быть, я не знаю).

Я также создал новый проект Windows Forms и сделал там то же самое, и он отлично работает, поэтому, должно быть, проблема в том, как окна создаются и закрепляются в движке 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 ]

21 голосов
/ 07 мая 2009

Я наконец понял это после 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;
        }
    }
10 голосов
/ 08 мая 2009

Проверьте мой собственный вопрос об этой самой вещи. в конце концов, все, что вам нужно, это что-то вроде этого:

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

Почему мое текстовое поле WPF "вроде" только для чтения?

6 голосов
/ 19 марта 2012

Нет необходимости создавать производное TextBox. Код для IOTextBox можно использовать в текстовых полях хостинга UserControl. Я успешно протестировал его с WPF-контролем, используемым для страницы пользовательских настроек, используемой в пакете VS2010.

6 голосов
/ 15 марта 2011

У меня похожая проблема с родительским окном 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;
        }
...