我正在处理WPF应用程序。我有以下代码:
但是我从来没有到达ExpandFreeDraw方法开始处的断点:
[当我调用BeginInvoke方法时,我已经在UI线程上:
ExpandFreeDraw方法也应在UI线程上发生。由于以下原因,我以上下文空闲优先级调用它:
在BeginInvoke行之前,我将WPF扩展器的可见性从折叠更改为可见。它开始呈现其控件:其中一些控件是输入控件,我想对其进行验证(通过AdornerDecorator完成,使其看起来像输入控件具有红色的验证边框)。如果我在更改Expander的可见性后直接调用ExpandFreeDraw(只是在没有Dispatcher的ExpandFreeDraw()的情况下),那么我确实会到达ExpandFreeDraw方法开始处的断点:扩展器可见,但装饰器未正确应用-没有红色边框效果。
我使用下一个较低的优先级(即背景:Dispatcher.BeginInvoke获得相同的效果:
在这种情况下,我还可以在ExpandFreeDraw方法的开头到达断点。当我应用下一个优先级(即ContextIdle)时,就会重现我的问题-我没有到达提到的断点。
请注意,此功能在大多数情况下都有效,这就是我知道ContextIdle优先级是我想要的优先级,因为在大多数情况下,它确实将验证应用于输入控件(如果我将优先级降低为Background,则它已经没有)。这是因为赋予Dispatcher的优先级是ContextIdle,它比Render的优先级低-您可以在此处了解更多信息:http://www.jonathanantoine.com/2011/08/29/update-my-ui-now-how-to-wait-for-the-rendering-to-finish/)。
我想获得有关如何找出问题所在的帮助。为什么
在大多数情况下正确调用ExpandFreeDraw的方法,但是在其中一种情况下(我无法真正理解哪种情况),它不是吗?我该如何调试?
也许:
可能是后台操作从未完成?这就是为什么永远不执行具有ContextIdle优先级的操作的原因?如何解决?
我终于解决了。我的问题是,UI调度程序队列不断以较高的优先级(高于上下文空闲)来获取操作。
如果您按以下方式编写代码:
public MainWindow()
{
InitializeComponent();
Thread t = new Thread(() =>
{
Application.Current.Dispatcher.BeginInvoke(new Action(() => DoBackGround1()), DispatcherPriority.Background, null);
Application.Current.Dispatcher.BeginInvoke(new Action(() => Debug.WriteLine("Context-Idle")), DispatcherPriority.ContextIdle, null);
Application.Current.Dispatcher.BeginInvoke(new Action(() => Debug.WriteLine("Additional-Background")), DispatcherPriority.Background, null);
});
t.Name = "dispatcherTest";
t.Start();
}
private void DoBackGround1()
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(1000);
Debug.WriteLine("Background " + i);
}
}
您将在输出窗口中获得以下结果:
背景0背景1背景2背景3背景4背景5背景6背景7背景8背景9附加背景上下文空闲
Additional-Background操作是在context-idle操作之前执行的,即使它是在context-idle操作之后被排队到UI队列调度程序中的。这很简单,但是了解这个概念很重要。
我有一个代码检查我是否在UI线程上-如果是,请立即执行操作。否则,将其排入调度程序队列。当我将提到的动作(ExpandFreeDraw)强制进入UI队列(即使我已经在UI线程上)时,一切都对我有用:现在,该动作被调用,并且我还获得了所需的验证。