WPF与Win32控件互操作:键盘按键后焦点被转移问题
问题描述:
已有一个通过改写的MFC Grid控件,通过 WindowsFormsHost 承载在WPF界面中。选定某一单元格,按下键盘方向键(如 Right),此时焦点从MFC控件中跳出并被转移至WPF界面(此时MFC 控件无法接获到 KeyDown 消息, 正常情况下,MFC控件通过此消息事件选中按键所指单元格)。
通过类型定义可以看到,WindowsFormsHost 通过 HwndHost 进行实现,该类是一个用于WPF中嵌入其他技术框架所开发界面,并与之进行交互的抽象类,它继承了 IWin32Window、 IKeyboardInputSink,分别用于窗口句柄 及 键盘消息处理。
资料介绍:
1、 HwndHost 官方文档的注解部分可以找到WPF 和 Win32 互操作,这里给出了较为详细的WPF互操作相关信息,及对应的示例程序。
2、除官方文档外,还有 Adam Nathan的博客 亦有介绍。
解决方法:
基于 HwndHost 实现一个托管宿主类,重写 TranslateAcceleratorCore 方法,不再使用基类中的虚方法实现,并将在重写方法中使用 API 转发消息到 MFC 窗体。具体代码如下:

1 public class Win32Host : HwndHost 2 { 3 public static readonly DependencyProperty HandleProperty = DependencyProperty.Register("Handle", typeof(IntPtr), typeof(Win32Host), new PropertyMetadata(IntPtr.Zero)); 4 5 new public IntPtr Handle 6 { 7 get { return (IntPtr)GetValue(HandleProperty); } 8 set { SetValue(HandleProperty, value); } 9 } 10 protected override HandleRef BuildWindowCore(HandleRef hwndParent) 11 { 12 Handle = CreateWindowEx( 13 0, "static", "", 14 WS_CHILD | WS_VISIBLE | LBS_NOTIFY, 15 0, 0, 16 (int)Width, (int)Height, 17 hwndParent.Handle, 18 IntPtr.Zero, 19 IntPtr.Zero, 20 0); 21 return new HandleRef(this, Handle); 22 } 23 protected override void DestroyWindowCore(HandleRef hwnd) 24 { 25 DestroyWindow(hwnd.Handle); 26 } 27 28 protected override bool TranslateAcceleratorCore(ref MSG msg, ModifierKeys modifiers) 29 { 30 SendMessage(msg.hwnd, msg.message, msg.wParam, msg.lParam); 31 return true; 32 } 33 34 35 const int WS_CHILD = 0x40000000; 36 const int WS_VISIBLE = 0x10000000; 37 const int LBS_NOTIFY = 0x001; 38 [DllImport("user32.dll")] 39 internal static extern IntPtr CreateWindowEx(int exStyle, string className, string windowName, int style, int x, int y, int width, int height, IntPtr hwndParent, IntPtr hMenu, IntPtr hInstance, [MarshalAs(UnmanagedType.AsAny)] object pvParam); 40 [DllImport("user32.dll")] 41 static extern bool DestroyWindow(IntPtr hwnd); 42 [DllImport("user32.dll")] 43 public static extern IntPtr SetFocus(IntPtr hWnd); 44 [DllImport("user32.dll")] 45 public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); 46 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能