WinUI 3中如何设置窗口最小尺寸?UWP对应API返回null如何解决
WinUI 3 设置窗口最小尺寸方案
ApplicationView.GetForCurrentView() 是UWP应用模型下的专属API,WinUI 3基于桌面应用架构设计,不存在UWP的全局应用视图上下文,因此调用该接口返回null是预期行为,无法直接复用UWP的窗口尺寸设置逻辑。
WinUI 3设置窗口最小尺寸的通用实现方式是拦截Win32窗口消息,兼容性覆盖所有WinUI 3版本,具体实现如下:
- 首先引入所需命名空间
using System.Runtime.InteropServices; using WinRT.Interop; using Microsoft.UI.Xaml;
- 定义Win32 API相关的常量、结构体与P/Invoke签名
private const int WM_GETMINMAXINFO = 0x0024; private const int GWLP_WNDPROC = -4; [StructLayout(LayoutKind.Sequential)] private struct POINT { public int X; public int Y; } [StructLayout(LayoutKind.Sequential)] private struct MINMAXINFO { public POINT ptReserved; public POINT ptMaxSize; public POINT ptMaxPosition; public POINT ptMinTrackSize; public POINT ptMaxTrackSize; } private delegate nint WndProc(nint hWnd, uint msg, nint wParam, nint lParam, out bool handled); [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")] private static extern nint SetWindowLongPtr64(nint hWnd, int nIndex, nint dwNewLong); [DllImport("user32.dll", EntryPoint = "SetWindowLong")] private static extern nint SetWindowLongPtr32(nint hWnd, int nIndex, nint dwNewLong); [DllImport("user32.dll")] private static extern nint CallWindowProc(nint lpPrevWndFunc, nint hWnd, uint msg, nint wParam, nint lParam); private static nint SetWindowLongPtr(nint hWnd, int nIndex, nint dwNewLong) { return IntPtr.Size == 8 ? SetWindowLongPtr64(hWnd, nIndex, dwNewLong) : SetWindowLongPtr32(hWnd, nIndex, dwNewLong); }
- 在窗口构造函数中添加窗口子类化逻辑,拦截尺寸边界查询消息
// 目标最小尺寸,单位为物理像素 private const int MinWindowWidth = 500; private const int MinWindowHeight = 500; private nint _originalWndProc; private WndProc _customWndProc; public MainWindow() { InitializeComponent(); // 获取当前窗口的原生句柄 nint hWnd = WindowNative.GetWindowHandle(this); // 替换默认窗口过程 _customWndProc = ProcessWindowMessage; nint customWndProcPtr = Marshal.GetFunctionPointerForDelegate(_customWndProc); _originalWndProc = SetWindowLongPtr(hWnd, GWLP_WNDPROC, customWndProcPtr); } private nint ProcessWindowMessage(nint hWnd, uint msg, nint wParam, nint lParam, out bool handled) { handled = false; if (msg == WM_GETMINMAXINFO) { MINMAXINFO sizeInfo = Marshal.PtrToStructure<MINMAXINFO>(lParam); // 限制窗口最小可拖动尺寸 sizeInfo.ptMinTrackSize.X = MinWindowWidth; sizeInfo.ptMinTrackSize.Y = MinWindowHeight; Marshal.StructureToPtr(sizeInfo, lParam, true); handled = true; return 0; } // 非尺寸相关消息交给系统默认逻辑处理 return CallWindowProc(_originalWndProc, hWnd, msg, wParam, lParam); }
注意:上述代码中使用的尺寸单位是物理像素,如果需要和XAML布局使用的逻辑单位对齐,需要根据当前窗口DPI做换算:
物理像素值 = 逻辑单位值 * (当前DPI / 96.0),当前窗口DPI可通过DisplayInformation.GetForCurrentView().LogicalDpi获取。
简化实现(仅支持Windows App SDK 1.3+)
如果项目使用的Windows App SDK版本为1.3或更高,不需要手写P/Invoke,可直接通过框架提供的OverlappedPresenter接口设置最小尺寸:
using Microsoft.UI.Windowing; public MainWindow() { InitializeComponent(); nint hWnd = WindowNative.GetWindowHandle(this); WindowId windowId = Win32Interop.GetWindowIdFromWindow(hWnd); AppWindow appWindow = AppWindow.GetFromWindowId(windowId); if (appWindow.Presenter is OverlappedPresenter presenter) { presenter.MinWidth = 500; presenter.MinHeight = 500; } }
内容的提问来源于stack exchange,提问作者Hebele Hübele
相关产品推荐
相关产品推荐

