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

WPF窗口隐藏关闭按钮与禁用调整大小冲突问题求助

WPF自定义窗口按钮并禁用调整大小(保留默认窗口特性)

解决方案

不要直接移除WS_SYSMENU样式,而是通过修改系统菜单隐藏默认按钮,同时移除WS_SIZEBOX禁用调整大小,再拦截标题栏双击防止意外最大化。这种方式能完整保留窗口的阴影、圆角、动画等原生系统特性。

实现代码

P/Invoke定义

private const int GWL_STYLE = -16;
private const int WS_SIZEBOX = 0x00040000;

private const int SC_CLOSE = 0xF060;
private const int SC_MINIMIZE = 0xF020;
private const int SC_MAXIMIZE = 0xF030;
private const int MF_BYCOMMAND = 0x00000000;

private const int WM_NCLBUTTONDBLCLK = 0x00A3;

[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);

[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

[DllImport("user32.dll")]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

[DllImport("user32.dll")]
private static extern bool RemoveMenuItem(IntPtr hMenu, uint uPosition, uint uFlags);

[DllImport("user32.dll")]
private static extern IntPtr DefWindowProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

窗口初始化处理

重写窗口的OnSourceInitialized方法,添加核心逻辑:

protected override void OnSourceInitialized(EventArgs e)
{
    base.OnSourceInitialized(e);
    var hwnd = new WindowInteropHelper(this).Handle;

    // 移除WS_SIZEBOX样式,禁用窗口调整大小
    int currentStyle = GetWindowLong(hwnd, GWL_STYLE);
    SetWindowLong(hwnd, GWL_STYLE, currentStyle & ~WS_SIZEBOX);

    // 获取系统菜单,移除默认的最小化、最大化、关闭菜单项
    IntPtr systemMenu = GetSystemMenu(hwnd, false);
    RemoveMenuItem(systemMenu, (uint)SC_MINIMIZE, (uint)MF_BYCOMMAND);
    RemoveMenuItem(systemMenu, (uint)SC_MAXIMIZE, (uint)MF_BYCOMMAND);
    RemoveMenuItem(systemMenu, (uint)SC_CLOSE, (uint)MF_BYCOMMAND);

    // 挂钩窗口过程,拦截标题栏双击事件
    HwndSource source = HwndSource.FromHwnd(hwnd);
    source.AddHook(WndProc);
}

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    if (msg == WM_NCLBUTTONDBLCLK)
    {
        // 阻止标题栏双击触发最大化
        handled = true;
        return IntPtr.Zero;
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

自定义标题栏拖动补充

如果使用了完全自定义的标题栏,需要在标题栏控件的MouseDown事件中添加拖动逻辑:

private void CustomTitleBar_MouseDown(object sender, MouseButtonEventArgs e)
{
    if (e.LeftButton == MouseButtonState.Pressed)
    {
        DragMove();
    }
}

原理说明

直接移除WS_SYSMENU会破坏窗口与系统边框逻辑的关联,导致WS_SIZEBOX的移除失效。保留WS_SYSMENU但删除不需要的菜单项,既能隐藏默认按钮,又能让WS_SIZEBOX的修改正常生效,同时完整保留窗口的原生视觉特性(阴影、圆角)和行为(如窗口移动、系统动画)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 23:26:08