tags:

views:

125

answers:

1

Hi

I am facing one issue in which WPF application unable to update the progress bar even the button on the wpf window stop glowing untill i move the window then everything is fine.

I have try to call InvalidateRect everytime i update the progress bar which actually generate the WM_PAINT message but doesn't solve the issue. This issue is random some time happend some time doesn't happend.

My application is using DirectShow at the backened with Enhanced Video Rendering for video rendering. If i replace the Enhanced Video Renderer with VMR everything works fine.

I will appreciate if any one can help me .

Thanks Sohrab.

A: 

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.

Ray Burns