2

I'd like to prevent my window from being updated until I finish receiving data from the server and render it. Can I hook on the WM_PAINT event, or better still call some Win32API method to prevent the window from being updated and unfreeze it later?

More info: In the context of an MMC snapin written in C#, our application suffers from annoying flickering and double sorting behaviour: We use MMC's listViews, but since we subscribe to the sort event. MMC does it's own magic and sorts the page being displayed (and we can't override that), and when we receive a reply from our server we change the listView again. each row change is done sequentially, there's no beginUpdate etc. (AFAIK).

Daniel Rikowski
  • 71,375
  • 57
  • 251
  • 329
Yonatan Karni
  • 977
  • 2
  • 13
  • 32
  • I'm sorry but how do you make this work (hook into WM_PAINT) from mmc? I have the same problems on the tree view - heavy flickering when delete subnodes - each IConsoleNameSpace->DeleteItem calls WM_PAINT + WM_ERASEBKGND... – bgee Dec 07 '10 at 08:28
  • perhaps this link would help? http://msdn.microsoft.com/en-us/library/system.windows.forms.application.addmessagefilter.aspx - I didn't have to do this, since our problem was mainly with the listviews, and we completely replaced them with FormViews containing WPF listviews hosted in Winforms elementhost (~~yes we did!~~). but I also encountered this treeview flickering, might actually try this some day. – Yonatan Karni Dec 09 '10 at 16:06
  • First of all thanks. But in our case it have to be defined under mmc interfaces... I tried LockUpdateWindow, and it worked, but somehow it made other windows to flicker :) – bgee Dec 12 '10 at 07:55

3 Answers3

1

Normally hooking into WM_PAINT is the way to go, but make sure you also ignore all WM_ERASEBKGND notifcations, otherwise you'll still get flicker, because Windows erases the Windows area for you. (Return non-zero to prevent Windows from doing that)

One other possibility is to use the LockWindowUpdate function, but it has some drawbacks:

  • Only one window can be locked
  • Upon unlock the whole desktop and all sub-windows (i.e. everything) is repainted, resulting in short flash of the whole desktop. (It's worse on XP than on Vista)
Daniel Rikowski
  • 71,375
  • 57
  • 251
  • 329
1

Some controls have BeginUpdate and EndUpdate APIs for this purpose.

If you do something (e.g. hook and ignore paint events) do disable painting, then a way to force a repaint later is to call the Invalidate method.

ChrisW
  • 54,973
  • 13
  • 116
  • 224
  • That might be true in some environments, but AFAIK `Invalidate` just marks the whole window region as "invalid", so the next paint event repaints everything. Invalidate by itself does not force a repaint, it only forces that *when* a repaint is happening, everything is repainted. – Daniel Rikowski Oct 11 '09 at 14:14
  • Of course, that depends on the framework. In .NET Invalidate also triggers a paint event. – Daniel Rikowski Oct 11 '09 at 14:15
  • @DR there's also an `Update` method to force an immediate update after invalidate. SFAIK, invoking Update causes a synchrnous paint event, whereas just calling Invalidate results in an asynchronous paint, i.e. a WM_PAINT will be generated when the message queue is empty of any other messages. – ChrisW Oct 11 '09 at 14:21
0

OK, after all searching and checking I've found that LockUpdateWindow is bad idea - see for example articles of Raimond Chen OldNewThing. But even to implement the idea of SetRedrawWindow wasn't so simple - because what I had was only received from IConsole2* pConsole->GetMainWindow() HWND handler of main window. By setting it to SetRedraw = FALSE it was disappeared in very strange manner. Though to make the procedure run only for the TreeView and not for the whole application (ours left panel) I ran

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

where SetChildRedraw callback was defined in next way:

#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;
}
bgee
  • 989
  • 2
  • 13
  • 19