WPF Control issues

匆匆过客 提交于 2019-12-07 06:56:27

I understand why you tried WM_PAINT to fix your problem. However WM_PAINT really has nothing to do with WPF rendering at all.

Basically, here is how WPF does its rendering when a Window (or HwndSource, ElementHost, ...) is first shown on the screen:

  1. A Window object has its Visibility set to "Visible"
  2. A Win32 window (hWnd) is allocated and shown, but its WM_PAINT is ignored
  3. A Direct3D Surface is allocated to cover the Win32 window's area
  4. A Dispatcher callback is scheduled at DispatcherPriority.Render
  5. When the Dispatcher callback fires, the window's visual tree is measured and arranged
  6. During the arrange pass every control generates drawing instructions to draw itself and stores these in a DrawingContext
  7. At the end of the arrange pass WPF reads the DrawingContext data and uses Direct3D to update the screen

From then on, any time a property change is made that affects the display, relevant portions of steps 4-7 are repeated in an extremely efficient incremental fashion, updating only what needs to be updated.

The key thing to note here is that any time there is rendering work to be done, a Dispatcher callback is scheduled to do it. This means that your UI will continue to render as long as:

  1. The Dispatcher is processing its queue, and
  2. You aren't continuously adding dispatcher operations at or above Render priority

In addition, processing of input events happens at Input priority, so you need to at least allow the Dispatcher to execute down to Input priority if you want mouse over to work on buttons.

Because of the way WPF works, sending WM_PAINT doesn't do anything at all. What you want to do is to give the Dispatcher a chance to process its queue. Generally this is done by calling Dispatcher.Invoke from the UI thread and passing a priority lower than the events you want to flush, for example:

Dispatcher.Invoke(DispatcherPriority.ApplicationIdle, new Action(() => {}));

Notice that the action does nothing at all. But the call to Dispatcher.Invoke cannot return until the empty action executes, and the empty action cannot execute until all higher priority actions execute. So the above code has the effect of forcing the rendering to happen synchronously, similar to what would happen when doing SendMessage(WM_PAINT, ...) in Win32.

One way do diagnose the problem is to set a DispatcherTimer to periodically write to the console. By running this timer at various priority levels you can determine what is holding up the Dispatcher queue. If nothing is running at any level it is probably something external locking up the UI thread, in which case breaking the process and checking the stack may help. A profiling tool is even better for this. In each case, determine whether the process is executing code or waiting for a lock. If it is executing code, figure out why that code never returns to give the Dispatcher a chance to run. If it is waiting for a lock, figure out who is holding that lock.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!