2

我想防止我的窗口被更新,直到我完成从服务器接收数据并呈现它。我可以挂钩 WM_PAINT 事件,还是更好地调用一些 Win32API 方法来防止窗口被更新并在以后解冻它?

更多信息: 在用 C# 编写的 MMC 管理单元的上下文中,我们的应用程序会遇到烦人的闪烁和双重排序行为:我们使用 MMC 的 listViews,但因为我们订阅了排序事件。MMC 使用它自己的魔法并对正在显示的页面进行排序(我们不能覆盖它),当我们收到来自服务器的回复时,我们再次更改 listView。每行更改都是按顺序完成的,没有 beginUpdate 等(AFAIK)。

4

3 回答 3

1

通常挂钩WM_PAINT是要走的路,但请确保您也忽略所有WM_ERASEBKGND通知,否则您仍然会闪烁,因为 Windows 会为您擦除 Windows 区域。(返回非零以防止 Windows 这样做)

另一种可能性是使用该LockWindowUpdate功能,但它有一些缺点:

  • 只能锁定一个窗口
  • 解锁整个桌面后,所有子窗口(即一切)都被重新绘制,导致整个桌面短暂闪烁。(在 XP 上比在 Vista 上更糟)
于 2009-10-11T14:08:37.127 回答
1

一些控件具有用于此目的BeginUpdateEndUpdateAPI。

如果你做了一些事情(例如钩子和忽略绘制事件)禁用绘制,那么稍后强制重新绘制的一种方法是调用该Invalidate方法。

于 2009-10-11T14:09:03.320 回答
0

好的,经过所有搜索和检查后,我发现 LockUpdateWindow 是个坏主意 - 例如参见 Raimond Chen OldNewThing的文章。但即使实现 SetRedrawWindow 的想法也不是那么简单——因为我所拥有的只是从主窗口的 IConsole2* pConsole->GetMainWindow() HWND 处理程序收到的。通过将其设置为 SetRedraw = FALSE,它以非常奇怪的方式消失了。尽管为了使该过程仅针对 TreeView 而不是针对整个应用程序(我们的左面板)运行,但我运行了

EnumChildWindows(hWnd, SetChildRedraw, FALSE); //stopping redraw
//... here you do your operations
EnumChildWindows(hWnd, SetChildRedraw, TRUE); //restarting redraw

其中 SetChildRedraw 回调以下一种方式定义:

#define DECLARE_STRING(str) TCHAR str[MAX_PATH]; ZeroMemory(str, sizeof(str));
BOOL CALLBACK SetChildRedraw(HWND hwndChild, LPARAM lParam) 
{ 
    RECT rcChildRect; ZeroMemory(&rcChildRect, sizeof(rcChildRect));
    DECLARE_STRING(sText)
    GetClassName(hwndChild, sText, MAX_PATH);
    if (wcsstr(sText, L"SysTreeView32") != NULL)
    {
        SetWindowRedraw(hwndChild, lParam);
        if (lParam == TRUE)
        {
            GetWindowRect(hwndChild, &rcChildRect);
            InvalidateRect(hwndChild, &rcChildRect, TRUE);
        }
    }
    return TRUE;
}
于 2010-12-15T07:12:38.117 回答