WPF控制问题

1 wpf directshow

我面临一个问题,其中WPF应用程序无法更新进度条甚至wpf窗口上的按钮停止发光,直到我移动窗口然后一切都很好.

每次我更新实际生成WM_PAINT消息但没有解决问题的进度条时,我都尝试调用InvalidateRect.这个问题是随机发生的,有些时候不会发生.

我的应用程序在后台使用DirectShow,增强视频渲染用于视频渲染.如果我用VMR替换增强型视频渲染器一切正常.

如果有人能帮助我,我将不胜感激.

谢谢Sohrab.

Ray*_*rns 7

我理解为什么你尝试WM_PAINT来解决你的问题.但是,WM_PAINT根本与WPF渲染无关.

基本上,这是WPF在屏幕上首次显示Window(或HwndSource,ElementHost,...)时的渲染方式:

  1. Window对象的Visibility设置为"Visible"
  2. 分配并显示Win32窗口(hWnd),但忽略其WM_PAINT
  3. 分配Direct3D Surface以覆盖Win32窗口的区域
  4. 在DispatcherPriority.Render上安排Dispatcher回调
  5. 当Dispatcher回调触发时,将测量并排列窗口的可视树
  6. 在排列过程中,每个控件都会生成绘图指令以绘制自身并将它们存储在DrawingContext中
  7. 在安排传递结束时,WPF读取DrawingContext数据并使用Direct3D更新屏幕

从那时起,每当进行影响显示的属性改变时,步骤4-7的相关部分以极其有效的增量方式重复,仅更新需要更新的内容.

这里需要注意的关键是,只要有渲染工作要完成,就会安排Dispatcher回调.这意味着您的UI将继续呈现,只要:

  1. Dispatcher正在处理其队列,并且
  2. 您不会持续添加处于渲染优先级或以上的调度程序操作

此外,输入事件的处理发生在输入优先级,因此如果您希望鼠标悬停在按钮上,则至少需要让Dispatcher执行输入优先级.

由于WPF的工作方式,发送WM_PAINT根本不做任何事情.你想要做的是让Dispatcher有机会处理它的队列.通常,这是通过从UI线程调用Dispatcher.Invoke并传递低于要刷新的事件的优先级来完成的,例如:

Dispatcher.Invoke(DispatcherPriority.ApplicationIdle, new Action(() => {}));
Run Code Online (Sandbox Code Playgroud)

请注意,该操作根本不起作用.但是,在执行空操作之前,对Dispatcher.Invoke的调用无法返回,并且在执行所有优先级较高的操作之前,空操作无法执行.因此上面的代码具有强制渲染同步发生的效果,类似于在Win32中执行SendMessage(WM_PAINT,...)时会发生的情况.

诊断问题的一种方法是设置DispatcherTimer以定期写入控制台.通过以各种优先级运行此计时器,您可以确定阻塞Dispatcher队列的内容.如果没有任何级别正在运行,则可能是外部锁定UI线程的东西,在这种情况下,破坏进程并检查堆栈可能会有所帮助.分析工具对此更好.在每种情况下,确定进程是执行代码还是等待锁定.如果它正在执行代码,请弄清楚为什么该代码永远不会返回以给Dispatcher一个运行的机会.如果它正在等待锁定,找出谁持有该锁定.