如何创建恰好填满WPF窗口可用空间的位图
WPF窗口内容区物理像素尺寸获取方案
要在WPF布局执行前、Content为null的状态下精确拿到内容渲染区域的物理像素数,直接通过Win32接口获取客户区尺寸即可,完全避开WPF布局系统和依赖属性的限制。
核心实现逻辑
- 选择
SourceInitialized事件作为取值时机:该事件触发时窗口句柄已完成创建,早于WPF子控件布局流程,此时Window.Content为null也不影响取值操作 - 调用Win32原生
GetClientRect接口:该接口直接返回窗口排除标题栏、边框等非客户区的纯内容区域尺寸,返回值单位为物理像素,无需额外做DPI转换 - 提前开启Per-Monitor V2 DPI感知:在应用程序清单中配置DPI感知等级,避免系统DPI虚拟化导致返回值和实际物理像素不匹配
代码实现
首先引入所需的Win32互操作定义:
using System; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Imaging; [StructLayout(LayoutKind.Sequential)] internal struct RECT { public int Left; public int Top; public int Right; public int Bottom; } internal partial class NativeMethods { [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect); }
在窗口类中完成像素尺寸获取和位图创建:
public partial class PixelRenderWindow : Window { public PixelRenderWindow() { InitializeComponent(); SourceInitialized += OnSourceInitialized; } private void OnSourceInitialized(object sender, EventArgs e) { IntPtr hWnd = new WindowInteropHelper(this).Handle; NativeMethods.GetClientRect(hWnd, out RECT clientArea); // 直接获得所需的物理像素计数 int horizontalPixelCount = clientArea.Right; int verticalPixelCount = clientArea.Bottom; // 按原逻辑创建位图 int[] pixelBuffer = new int[horizontalPixelCount * verticalPixelCount]; DpiScale dpi = VisualTreeHelper.GetDpi(this); BitmapSource renderBitmap = BitmapSource.Create( horizontalPixelCount, verticalPixelCount, dpi.PixelsPerInchX, dpi.PixelsPerInchY, PixelFormats.Bgr32, null, pixelBuffer, horizontalPixelCount * 4); Content = new Image { Source = renderBitmap }; } }
方案适配性说明
- 不依赖
Window.ActualWidth/Window.ActualHeight属性,返回值完全排除窗口非客户区尺寸 - 不需要访问
Window.Content属性,Content为null时可正常执行 - 返回值直接为物理像素计数,和
BitmapSource.Create所需的像素维度参数完全匹配,无需额外做单位转换 - 对默认窗口样式、
WindowStyle=None自定义无边框窗口均生效
内容的提问来源于stack exchange,提问作者Peter Huber
相关产品推荐
相关产品推荐

