2009-10-11 3 views
2

Я бы хотел, чтобы мое окно не обновлялось до тех пор, пока я не получу данные с сервера и не сделаю его. Можно ли подключиться к событию WM_PAINT или еще лучше вызвать некоторый метод Win32API, чтобы предотвратить обновление окна и размораживание его позже?Как остановить рендеринг окна и позже возобновить?

Подробнее: В контексте MMC оснастки, написанной в C#, наше приложение страдает от раздражающего мерцания и двойного поведения сортировки: Мы используем ListViews MMC, но так как мы подписываемся на событие сортировки. MMC делает свою собственную магию и сортирует отображаемую страницу (и мы не можем ее переопределить), и когда мы получаем ответ от нашего сервера, мы снова меняем listView. каждое изменение строки выполняется последовательно, нет beginUpdate и т. Д. (AFAIK).

+0

Мне очень жаль, но как вы делаете эту работу (зацепите WM_PAINT) от mmc? У меня те же проблемы на древовидном представлении - тяжелое мерцание при удалении подузлов - каждый IConsoleNameSpace-> DeleteItem вызывает WM_PAINT + WM_ERASEBKGND ... – bgee

+0

Возможно, эта ссылка поможет? http://msdn.microsoft.com/en-us/library/system.windows.forms.application.addmessagefilter.aspx - Мне не нужно было это делать, поскольку наша проблема была в основном с listviews, и мы полностью заменили их с FormViews, содержащими списки просмотров WPF, размещенные в Winforms elementhost (~~ да, мы сделали! ~~). но я также столкнулся с этим мерцанием древовидной структуры, может на самом деле попробовать это однажды. –

+0

Прежде всего спасибо. Но в нашем случае это должно быть определено в интерфейсах mmc ... Я попытался LockUpdateWindow, и он сработал, но каким-то образом он заставил другие окна мерцать :) – bgee

ответ

1

Обычно подключаться к WM_PAINT - это путь, но не забывайте обо всех WM_ERASEBKGND notifcations, иначе вы все равно будете мерцать, потому что Windows стирает для вас область Windows. (Возврат ненулевым, чтобы предотвратить Windows, делать это)

Еще одна возможность заключается в том, чтобы использовать функцию LockWindowUpdate, но она имеет некоторые недостатки:

  • только одно окно может быть заблокирован
  • Upon отпереть весь рабочий стол и все под-окна (т.е. все) перекрашены, что приводит к короткой вспышке всего рабочего стола. (Это хуже, чем XP на Vista,)
+0

Прошу прощения, но как вы это делаете (подключаясь к WM_PAINT) от mmc? – bgee

1

Некоторые элементы управления имеют BeginUpdate и EndUpdate API-интерфейсы для этой цели.

Если вы что-то делаете (например, перехватываете и игнорируете события рисования), отключите рисование, тогда способ принудительно перекрасить позже - вызвать метод Invalidate.

+0

Это может быть правдой в некоторых средах, но AFAIK 'Invalidate' просто маркирует весь область окна как« недействительный », поэтому следующее событие рисования реплицирует все. Недействительный сам по себе не заставляет перерисовать, он только заставляет это * когда * происходит перекраска, все перекрашено. –

+0

Конечно, это зависит от рамки. В .NET Invalidate также запускается событие рисования. –

+0

@DR есть также метод «Обновить», чтобы принудительно выполнить немедленное обновление после недействительности. SFAIK, вызывающий обновление вызывает синхронное событие рисования, тогда как просто вызов Invalidate приводит к асинхронной краске, то есть WM_PAINT будет генерироваться, когда очередь сообщений не будет содержать никаких других сообщений. – ChrisW

0

ОК, после всех поисков и проверок я обнаружил, что LockUpdateWindow - плохая идея - см., Например, статьи Раймонда Чена 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; 
} 
Смежные вопросы