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

C#开发WinUI 3如何通过WM_GETMINMAXINFO设置窗口大小限制

实现位置选择

相关窗口尺寸约束逻辑必须写在需要控制尺寸的对应窗口类(如默认项目模板的MainWindow)中,不要写在App类里:

  • WM_GETMINMAXINFO是系统发送给单个窗口句柄的私有消息,和具体窗口实例强绑定
  • App类仅负责全局应用生命周期管理,不直接持有目标窗口的句柄引用,写在此处需要额外做窗口枚举、句柄匹配,徒增不必要的复杂度
  • 多窗口场景下,逻辑写在各自窗口类中可以为不同窗口单独配置不同的尺寸限制,互不干扰

具体实现方案

根据你使用的Windows App SDK版本,可以选两种实现方式:

方案1:Windows App SDK 1.3+ 原生API(推荐)

1.3及以上版本框架已经封装了尺寸限制能力,不需要手动处理Win32消息,直接调用内置API即可:

using Microsoft.UI.Windowing;

// 在MainWindow构造函数中InitializeComponent()后添加
public MainWindow()
{
    InitializeComponent();

    var appWindow = this.AppWindow;
    // 设置最小尺寸,单位为物理像素
    appWindow.ResizeManager.MinSize = new Windows.Graphics.SizeInt32(800, 600);
    // 设置最大尺寸,不需要限制可删除此行
    appWindow.ResizeManager.MaxSize = new Windows.Graphics.SizeInt32(1920, 1080);
}

该方案底层已经自动处理了WM_GETMINMAXINFO消息的拦截和参数填充,稳定性更高,代码量最少。

方案2:手动处理WM_GETMINMAXINFO消息(兼容所有版本)

如果使用的是1.3以下版本的Windows App SDK,可以通过窗口子类化拦截消息实现:

  1. 首先在窗口类中定义所需的Win32互操作结构、常量和函数导入:
using System.Runtime.InteropServices;

private const int WM_GETMINMAXINFO = 0x0024;

[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
    public int X;
    public int Y;
    public POINT(int x, int y) { X = x; Y = 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, nint uIdSubclass, nint dwRefData);
private WndProc _wndProc; // 必须定义为实例字段,防止被GC回收

[DllImport("Comctl32.dll", CharSet = CharSet.Auto)]
private static extern bool SetWindowSubclass(nint hWnd, WndProc pfnSubclass, nint uIdSubclass, nint dwRefData);

[DllImport("Comctl32.dll", CharSet = CharSet.Auto)]
private static extern nint DefSubclassProc(nint hWnd, uint msg, nint wParam, nint lParam);
  1. 在MainWindow构造函数中安装窗口子类钩子:
public MainWindow()
{
    InitializeComponent();

    _wndProc = CustomWindowProc;
    nint hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
    SetWindowSubclass(hwnd, _wndProc, nint.Zero, nint.Zero);
}
  1. 实现自定义窗口过程,拦截WM_GETMINMAXINFO修改尺寸限制:
private nint CustomWindowProc(nint hWnd, uint msg, nint wParam, nint lParam, nint uIdSubclass, nint dwRefData)
{
    if (msg == WM_GETMINMAXINFO)
    {
        MINMAXINFO mmi = Marshal.PtrToStructure<MINMAXINFO>(lParam);
        // 设置最小拖拽尺寸
        mmi.ptMinTrackSize = new POINT(800, 600);
        // 设置最大拖拽尺寸,不需要限制可删除此行
        mmi.ptMaxTrackSize = new POINT(1920, 1080);
        
        Marshal.StructureToPtr(mmi, lParam, false);
        return 0;
    }
    return DefSubclassProc(hWnd, msg, wParam, lParam);
}

注意事项

  • 上述所有API中使用的尺寸单位均为物理像素,不是WinUI XAML中默认使用的有效像素(EPX)。如果需要和XAML设计尺寸严格对齐,需要根据当前显示器DPI做单位换算:物理像素 = 有效像素 * (系统DPI / 96)
  • 不要尝试在App类中安装全局窗口钩子拦截消息,会增加全局消息处理开销,还容易引发多窗口场景下的逻辑冲突
  • 存储窗口过程委托的_wndProc字段不能写成方法内的局部变量,否则会被GC回收,触发访问违例崩溃

内容的提问来源于stack exchange,提问作者user19414975

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 00:27:22