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
相关产品推荐
相关产品推荐

