在 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;
}
如果这个答案有助于澄清问题,请将其标记为已接受,以便其他人可以更轻松地找到它。