news 2026/4/14 14:12:08

WPF如何页面内嵌窗口

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
WPF如何页面内嵌窗口

简介

  • 什么是XAML

  • 什么是句柄(IntPtr)

  • HwndHost是什么

  • 什么是空域

什么是XAML

XAML 是 eXtensible Application Markup Language 的缩写,中文常称为可扩展应用程序标记语言。它是微软为 .NET 平台(特别是 WPF、UWP、WinUI、Xamarin.Forms/Maui 等)创建的一种声明式标记语言

什么是句柄(IntPtr)

句柄 是 Handle 的中文翻译,是 Windows 操作系统中一个极其重要的核心概念。你可以把它理解为操作系统资源的"身份证号"或"引用凭证",简单的理解你可以理解为每个窗口都是一个句柄,开发者不需要知道资源在内存中的具体位置,只需要通过句柄操作即可。

HwndHost是什么

HwndHost是 WPF 中用于托管 Win32 控件的基类。它本质上是一个 "窗口包装器",让传统的 Win32 控件能够在 WPF 应用程序中运行。

什么是空域

空域问题是 WPF 中嵌入 Win32 控件时的核心限制。简单说就是 "WPF 和 Win32 控件不能在同一区域共存"。用人话说就是目标控件与HwndHost在同一层级,用户控件位于HwndHost之上,理论上是控件会覆盖HwndHost,但是实际上不是,HwndHost会悬浮在控件之上,这种问题简称空域,造成这种问题的根本原因是技术实现不同。

  • WPF:使用 DirectX,支持 GPU 加速、矢量图形、透明度、3D 变换

  • Win32:使用 GDI/GDI+,基于像素、无硬件加速、不支持透明度

具体表现现象

  • 遮挡问题

<Grid> <!-- Win32 控件 --> <local:HwndHostControl Width="200" Height="200"/> <!-- 这个按钮会被挖掉一半! --> <Button Content="我在上面" Width="100" Height="30" Canvas.Left="150" Canvas.Top="150"/></Grid>
  • 透明无效

<Grid> <!-- 设置透明背景没用! --> <local:HwndHostControl Background="Transparent"> <!-- Win32 控件不支持 WPF 透明度 --> </local:HwndHostControl> <!-- 这个控件显示不出来 --> <Border Background="Red"/></Grid>

实现逻辑

  • 创建自定义控件,继承HwndHost,实现BuildWindowCore、DestroyWindowCore

public class HwndHostControl : HwndHost{ protected override HandleRef BuildWindowCore(HandleRef hwndParent) { throw new NotImplementedException(); } protected override void DestroyWindowCore(HandleRef hwnd) { throw new NotImplementedException(); }}
  • 创建Win32API控制句柄

[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr CreateWindowExW( uint dwExStyle, [MarshalAs(UnmanagedType.LPWStr)] string lpClassName, [MarshalAs(UnmanagedType.LPWStr)] string lpWindowName, uint dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, [MarshalAs(UnmanagedType.AsAny)] object pvParam); /// <summary> /// 设置窗口的父窗口(改变所有权与 Z 序关系)。返回旧父窗口句柄。 /// </summary> [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); /// <summary> /// 销毁窗口,释放系统资源。销毁后句柄变为无效。 /// </summary> [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool DestroyWindow(IntPtr hwnd); /// <summary> /// 移动并调整窗口大小,可选是否重绘(bRepaint)。 /// </summary> [DllImport("user32.dll", SetLastError = true)] private static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
  • 获取窗口句柄(本教程以记事本为例子)

Process.GetProcessesByName("notepad").First().MainWindowHandle
  • 创建子窗口句柄

var _parentHwnd = CreateWindowExW(0x00000020u, "static", null, 0x40000000u | 0x10000000u, 0, 0, 0, 0, hwndParent.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
  • 将获取的目标句柄填充到子窗口句柄上

SetParent(_childHwnd, _parentHwnd);
  • 动态绘制句柄窗口大小

protected override void OnRender(DrawingContext drawingContext){ base.OnRender(drawingContext); UpdateWindowPos(); MoveWindow(_childHwnd, 0, (int)(0), (int)ActualWidth, (int)ActualHeight, true);}
  • 释放句柄

protected override void DestroyWindowCore(HandleRef hwnd) { DestroyWindow(hwnd.Handle); }

效果图

注意

本文章目的是给初步了解学习WPF相关人员参考,并未涉及到非常底层的句柄以及内存相关的原理讲解,为快速集成窗体项目做准备。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/20 9:42:48

5分钟搞定B站缓存转换:零技术门槛的完整解决方案

还在为B站缓存视频无法播放而烦恼吗&#xff1f;m4s-converter工具采用先进的GPAC MP4Box技术&#xff0c;让转换过程变得前所未有的简单。作为一款专为普通用户设计的B站缓存转换工具&#xff0c;它能够将复杂的m4s文件转换为通用的MP4格式&#xff0c;支持全平台设备播放。 【…

作者头像 李华
网站建设 2026/4/13 13:30:01

番茄小说本地化保存解决方案深度剖析

番茄小说本地化保存解决方案深度剖析 【免费下载链接】fanqienovel-downloader 下载番茄小说 项目地址: https://gitcode.com/gh_mirrors/fa/fanqienovel-downloader 在数字化阅读日益普及的今天&#xff0c;如何确保心仪的小说内容能够长久保存并随时随地阅读&#xff…

作者头像 李华
网站建设 2026/4/14 11:19:31

Calibre-Web图书元数据插件完整配置教程:解决新版API缺失问题

Calibre-Web图书元数据插件完整配置教程&#xff1a;解决新版API缺失问题 【免费下载链接】calibre-web-douban-api 新版calibre-web已经移除douban-api了&#xff0c;添加一个豆瓣api实现 项目地址: https://gitcode.com/gh_mirrors/ca/calibre-web-douban-api 随着Cal…

作者头像 李华
网站建设 2026/4/14 14:52:52

驾驶证换证提醒:到期前自动拨打语音通知

驾驶证换证提醒&#xff1a;到期前自动拨打语音通知 在城市交通管理的日常运作中&#xff0c;一个看似微小却影响深远的问题正悄然浮现——每年有数千万驾驶人面临驾驶证到期未及时更换的情况。这不仅可能导致个人出行受阻&#xff0c;还可能因“无证驾驶”触碰法律红线。尽管各…

作者头像 李华
网站建设 2026/4/14 21:54:53

抖音下载工具终极指南:无水印高清视频与直播一键获取

抖音下载工具终极指南&#xff1a;无水印高清视频与直播一键获取 【免费下载链接】douyin-downloader 项目地址: https://gitcode.com/GitHub_Trending/do/douyin-downloader 还在为错过精彩抖音内容而懊恼吗&#xff1f;&#x1f914; 那些转瞬即逝的优质视频、无法重…

作者头像 李华
网站建设 2026/4/14 4:28:51

搭建AI Agent开发环境:必要工具与框架

搭建AI Agent开发环境:必要工具与框架 关键词:AI Agent、开发环境、必要工具、框架、搭建 摘要:本文旨在详细介绍搭建AI Agent开发环境所需的必要工具与框架。通过深入剖析每个环节,从背景知识的铺垫,到核心概念、算法原理的讲解,再到实际的项目实战案例分析,为开发者提…

作者头像 李华