You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

嵌入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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 10:12:32