如何设置WPF窗口最小化目标坐标 解决WS_EX_NOACTIVATE导致的位置异常
解决方案
你可以通过Windows API操作WINDOWPLACEMENT结构体来自定义窗口最小化的目标坐标,完全可以实现两个窗口最小化动画同步的需求,具体实现步骤如下:
步骤1:导入所需Win32 API
在WPF项目中添加如下API声明:
[StructLayout(LayoutKind.Sequential)] public struct POINT { public int X; public int Y; } [StructLayout(LayoutKind.Sequential)] public struct WINDOWPLACEMENT { public int length; public int flags; public int showCmd; public POINT ptMinPosition; public POINT ptMaxPosition; public RECT rcNormalPosition; } [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; } [DllImport("user32.dll")] private static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl); [DllImport("user32.dll")] private static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl); private const int WM_SYSCOMMAND = 0x0112; private const int SC_MINIMIZE = 0xF020; private const int SW_MINIMIZE = 6;
步骤2:拦截窗口消息自定义最小化坐标
给背景窗口重写消息处理逻辑,在触发最小化之前同步主窗口的最小化坐标:
private IntPtr _bgWindowHandle; // 背景窗口Loaded事件中初始化句柄和消息钩子 private void Window_Loaded(object sender, RoutedEventArgs e) { _bgWindowHandle = new WindowInteropHelper(this).Handle; HwndSource.FromHwnd(_bgWindowHandle).AddHook(WndProc); } private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if (msg == WM_SYSCOMMAND && wParam.ToInt32() == SC_MINIMIZE) { // 获取主窗口的最小化坐标 IntPtr mainWindowHandle = new WindowInteropHelper(/* 传入你的主窗口实例 */).Handle; WINDOWPLACEMENT mainPlacement = new WINDOWPLACEMENT(); mainPlacement.length = Marshal.SizeOf(mainPlacement); GetWindowPlacement(mainWindowHandle, ref mainPlacement); // 同步设置背景窗口的最小化坐标 WINDOWPLACEMENT bgPlacement = new WINDOWPLACEMENT(); bgPlacement.length = Marshal.SizeOf(bgPlacement); GetWindowPlacement(_bgWindowHandle, ref bgPlacement); bgPlacement.ptMinPosition = mainPlacement.ptMinPosition; bgPlacement.showCmd = SW_MINIMIZE; SetWindowPlacement(_bgWindowHandle, ref bgPlacement); } return IntPtr.Zero; }
步骤3:最小化完成后隐藏背景窗口
监听主窗口的StateChanged事件,当主窗口完全进入最小化状态后,将背景窗口设置为Visibility.Collapsed即可。窗口还原时先恢复背景窗口显示,再同步坐标,不影响原生动画效果。
注意事项
- 你当前设置的
WS_EX_NOACTIVATE扩展样式可以保留,不影响上述逻辑执行 - 如果需要自定义最小化到任意位置(比如类似Rocket Dock的 dock 栏位置),直接给
ptMinPosition赋值目标坐标即可
内容的提问来源于stack exchange,提问作者Selastin
相关产品推荐
相关产品推荐

