嵌入Autodesk Inventor的Avalonia窗口文本框无法接收输入
解决Autodesk Inventor可停靠窗口中Avalonia控件的键盘输入问题
问题场景
开发Autodesk Inventor插件时,使用Avalonia构建UI并嵌入到Inventor的可停靠窗口中,其他功能正常,但Avalonia文本框仅能接收退格、删除键,其他按键无响应;而从功能区按钮启动独立Avalonia窗口时无此问题。
尝试过通过AvaloniaHwndHost将Avalonia嵌入WPF窗口再加入可停靠窗口,问题依旧。Autodesk论坛中针对WPF控件的修复方案(通过WM_GETDLGCODE钩子返回对话框代码)对Avalonia控件无效。
原因分析
Inventor可停靠窗口作为父容器,会拦截大部分键盘消息,仅允许少数按键传递给子控件。WPF的修复方案是让WPF窗口告知父窗口需要所有键盘消息,但Avalonia的消息循环与WPF分离,因此需要将键盘消息从WPF宿主窗口转发到Avalonia的消息队列。
解决方案
需要两步处理:确保WPF宿主窗口能从Inventor获取所有键盘消息,再将这些消息转发给Avalonia控件的窗口句柄。
1. 获取WPF窗口与Avalonia控件句柄
在插件激活方法中,初始化WPF窗口并获取AvaloniaHwndHost的句柄:
private IntPtr _avaloniaHandle; public void Activate(ApplicationAddInSite addInSiteObject, bool firstTime) { // 初始化WPF宿主窗口 var wpfWindow = new WpfWindow(); wpfWindow.WindowStyle = System.Windows.WindowStyle.None; wpfWindow.ResizeMode = System.Windows.ResizeMode.NoResize; wpfWindow.Visibility = System.Windows.Visibility.Visible; // 获取WPF窗口句柄 var wpfHelper = new WindowInteropHelper(wpfWindow); wpfHelper.EnsureHandle(); var wpfHandle = wpfHelper.Handle; // 加载完成后获取Avalonia宿主的句柄 var avaloniaHost = wpfWindow.AvaloniaHost; avaloniaHost.Loaded += (s, e) => { // 根据AvaloniaHwndHost的实际属性获取句柄,部分版本可能是NativeHandle _avaloniaHandle = avaloniaHost.Handle; }; // 创建Inventor可停靠窗口并添加WPF窗口 var dockableWindow = InventorApplication.UserInterfaceManager.DockableWindows.Add( System.Guid.NewGuid().ToString(), "Test", "Test" ); dockableWindow.AddChild(wpfHandle); // 注册WPF窗口的消息钩子 HwndSource.FromHwnd(wpfHandle).AddHook(WndProc); }
2. 消息钩子与键盘消息转发
修改WndProc钩子,处理WM_GETDLGCODE确保获取所有键盘权限,并将键盘消息转发给Avalonia控件:
// 对话框代码常量 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; // 键盘消息常量 private const int WM_KEYDOWN = 0x0100; private const int WM_KEYUP = 0x0101; private const int WM_CHAR = 0x0102; private const int WM_SYSKEYDOWN = 0x0104; private const int WM_SYSKEYUP = 0x0105; private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { // 告知Inventor需要所有键盘消息 if (msg == WM_GETDLGCODE) { handled = true; return new IntPtr(DLGC_WANTCHARS | DLGC_WANTARROWS | DLGC_HASSETSEL | DLGC_WANTTAB | DLGC_WANTALLKEYS); } // 将键盘消息转发给Avalonia控件 if (_avaloniaHandle != IntPtr.Zero) { switch (msg) { case WM_KEYDOWN: case WM_KEYUP: case WM_CHAR: case WM_SYSKEYDOWN: case WM_SYSKEYUP: User32.SendMessage(_avaloniaHandle, msg, wParam, lParam); handled = true; break; } } return IntPtr.Zero; }
3. 添加P/Invoke声明
需要引入user32.dll的SendMessage方法用于转发消息:
using System.Runtime.InteropServices; public static class User32 { [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); }
4. 焦点配置
确保WPF宿主和Avalonia控件可获取焦点:
- WPF XAML中设置
WpfAvaloniaHost的Focusable="True"
<Grid> <interop:WpfAvaloniaHost x:Name="AvaloniaHost" Focusable="True" /> </Grid>
- Avalonia视图中设置文本框
Focusable="True"
<TextBox AcceptsReturn="True" Focusable="True" />
内容的提问来源于stack exchange,提问作者Bas Nederveen
相关产品推荐
相关产品推荐

