WPF或Win32有没有API可以判断窗口的停靠边缘状态

HoWe Yu 86 信誉分
2025-08-27T10:31:19.3+00:00

将窗口拖动至桌面边缘并松开时会触发自动停靠,此时会触发大小改变事件。

拖动窗口边缘时也会触发大小改变事件。

有没有方法判断是由什么行为触发了大小改变事件。

开发人员技术 | Windows Presentation Foundation
0 个注释 无注释
{count} 票

1 个答案

排序依据: 非常有帮助
  1. Danny Nguyen (WICLOUD CORPORATION) 3,520 信誉分 Microsoft 外部员工
    2025-09-30T09:14:26.6066667+00:00

    在 Win32 和 WPF 中,都没有系统直接提供的 “已停靠(docked)” 事件。Windows 的 Aero Snap(窗口贴靠/停靠)功能是在外壳/窗口管理器层面实现的。对于你的应用程序来说,你只能接收到 WM_SIZE(Win32)或 SizeChanged(WPF)事件。

    如果你需要区分普通的调整大小和窗口贴靠导致的调整大小,可以结合以下方法:

    1. Win32 方法 在窗口过程里处理 WM_SIZE,然后在调整大小后检查窗口位置:

    [DllImport("user32.dll")]
    static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
     
    WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
    placement.length = Marshal.SizeOf(placement);
     
    GetWindowPlacement(hwnd, ref placement);
     
    if (placement.showCmd == SW_SHOWNORMAL)
    {
        // 然后检查窗口矩形是否和工作区边界对齐
        var rect = new RECT();
        GetWindowRect(hwnd, out rect);
     
        var workArea = SystemParameters.WorkArea;
        if (rect.Left == workArea.Left && rect.Right == workArea.Right)
        {
            // 停靠在顶部或占满宽度
        }
        else if (rect.Left == workArea.Left)
        {
            // 停靠在左边
        }
        else if (rect.Right == workArea.Right)
        {
            // 停靠在右边
        }
    }
    

    核心思路是将窗口矩形和当前显示器的工作区进行比较,以判断是否被贴靠到左/右/上。

    2. WPF 方法 在 WPF 中同样没有直接的停靠信息。但你可以监听 SizeChanged,然后通过 WindowInteropHelper 获取底层 HWND 的位置:

    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);
     
        var hwnd = new WindowInteropHelper(this).Handle;
        HwndSource.FromHwnd(hwnd).AddHook(WndProc);
    }
     
    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == WM_SIZE)
        {
            RECT rect;
            GetWindowRect(hwnd, out rect);
     
            // 将 rect 与 SystemParameters.WorkArea 或显示器工作区比较
            // 判断是否处于贴靠状态
        }
        return IntPtr.Zero;
    }
    

    如果这个答案有助于澄清问题,请将其标记为已接受,以便其他人可以更轻松地找到它。


你的答案

问题作者可以将答案标记为“接受的答案”,这有助于用户了解已解决作者问题的答案。