WPF TextBox не принимает ввод, когда в ElementHost в окнах
Мы разрабатываем элемент управления пользовательского интерфейса в WPF для использования в существующем приложении Windows Forms/MFC (Rhino 3D).
Механизм приложения предоставляет возможность создать "док-станцию", которая по существу позволяет помещать элементы управления Windows Forms в дочернее окно, которое может состыковываться с интерфейсом Engines.
Я пытаюсь помещать простой текстовый элемент WPF внутри элемента управления ElementHost, который добавляется в Dockbar. Кажется, что на первый взгляд это работает нормально; но после попытки ввода в TextBox только определенные последовательности фактически отображаются в TextBox. DELETE, BACKSPACE, COPY, PASTE и ВЫБОР ТЕКСТА. Если вы наберете A-Z, 1-9 и т.д., Эти клавиши не отображаются.
У меня есть SCOURED сеть и вы слышали о ElementHost.EnableModelessKeyboardInterop()
, но это относится только к Windows WPF, созданным из формы. Я создаю WPF UserControls и размещаю их в элементе управления ElementHost.
Я увидел сообщение, в котором говорилось о Dispatcher.Run(), и это вроде работает, но нарушает остальную форму:
System.Windows.Threading.Dispatcher.Run();
События PreviewKeyUp, PreviewKeyDown, KeyUp и KeyDown запускаются в TextBox, но, увы, нет текст отображается в текстовом поле.
Я ничего не знаю о сообщениях Windows, но с помощью WinSpector я заметил, что из текстового поля не поступают сообщения 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);
Ответы
Ответ 1
Я, наконец, понял это после 2 дней головокружения...
В диалоговом окне MFC Dialog принимали сообщения 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;
}
}
Ответ 2
Проверьте мой собственный вопрос об этом. в конце концов, все, что вам нужно, это что-то вроде этого:
Window window1 = new Window();
ElementHost.EnableModelessKeyboardInterop(window1);
window1.Show();
Почему мой текстовый поле WPF "kinda" только для чтения?
Ответ 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;
}
Ответ 4
Нет необходимости создавать производные TextBox. Код для IOTextBox можно использовать в текстовых окнах размещения UserControl. Я успешно протестировал его с помощью элемента управления WPF, используемого для страницы настраиваемых параметров, используемой в пакете VS2010.