在调用本机方法 MoveWindow 期间闪烁

问题描述

我有一个 WPF 应用程序,它使用 Process.Start() 方法打开一个新进程 (Notepad.exe)。我编写了防止用户移动记事本窗口的代码,其中窗口的 Top 属性不能小于 130 像素。我使用了来自此 SO question 的信息,最终使用以下代码来管理此运动

这是我在移动目标窗口时定义的windows事件委托:

    protected void TargetMoved(IntPtr hWinEventHook,Hook.SWEH_Events eventType,IntPtr hWnd,Hook.SWEH_ObjectId idobject,long idChild,uint dwEventThread,uint dwmsEventTime)
    {
        if (hWnd == targethWnd &&
            eventType == Hook.SWEH_Events.EVENT_OBJECT_LOCATIONCHANGE &&
            idobject == (Hook.SWEH_ObjectId)Hook.SWEH_CHILDID_SELF)
        {
            rect = Hook.GetwindowRect(hWnd);
            int x = rect.Left;
            int y = rect.Top;
            int width = rect.Right - rect.Left;
            int height = rect.Bottom - rect.Top;

            if (rect.Left <= 0)
                x = 0;
            if (rect.Top <= 130)
                y = 130;
                
            UnsafeNativeMethods.MoveWindow(targethWnd,x,y,width,height,true);
            
        }
    }

这段代码工作正常,它使窗口保持在边界内,但有一个恼人的问题:当窗口被拖动到 130 像素标记上方时(当 Top 小于 130 时),窗口在它们之间来回闪烁我拖动它的位置,以及它停止的位置。

如何消除这种闪烁?

解决方法

当你拖动一个窗口时,WM_WINDOWPOSCHANGINGWM_WINDOWPOSCHANGED 会被发送到窗口过程,然后重新绘制更改。如果这个窗口过程是你自己创建的,那么你就可以处理这两条消息,把left和top限制为0和130。

case WM_WINDOWPOSCHANGING:
case WM_WINDOWPOSCHANGED:
{
    WINDOWPOS* pos = (PWINDOWPOS)lParam;
    if (pos->x <= 0)
        pos->x = 0;
    if (pos->y <= 130)
        pos->y = 130;
    return 0;
}

如果这不是你的窗口过程,你需要SetWindowSubclass,但是你不能跨线程子类化一个窗口,你还需要使用代码注入。

所以,对于记事本窗口,你不能简单地解决这个问题, 正如评论所说,您可以简单地将编辑控件集成到您自己的窗口中。然后像上面的代码一样处理窗口消息。