通过具有 ContextIdle 优先级的 Dispatcher.BeginInvoke 调用时永远不会执行委托
Delegate is never executed while invoked via Dispatcher.BeginInvoke with ContextIdle priority
我在开发 WPF 应用程序。
我有以下代码:
但是我从来没有到达 ExpandFreeDraw 方法开头的断点:
当我调用 BeginInvoke 方法时,我已经在 UI 线程上:
ExpandFreeDraw 方法也应该发生在 UI 线程上。
由于以下原因,我以上下文空闲优先级调用它:
在 BeginInvoke 行之前,我将 WPF Expander 的 Visibility 从 collapsed 更改为 Visible。它开始呈现它的控件:其中一些控件是输入控件,我想对它们应用验证(通过 AdornerDecorator 完成,这使得输入控件看起来像有一个红色验证边框)。
如果我在更改扩展器的可见性后直接调用 ExpandFreeDraw(只是没有 Dispatcher 的 ExpandFreeDraw()),我会到达 ExpandFreeDraw 方法开头的断点:扩展器可见但装饰器未正确应用 - 没有红色边框效果。
我得到与 Dispatcher.BeginInvoke 相同的效果,下一个较低的优先级,即背景:
在那种情况下,我也到达了 ExpandFreeDraw 方法开头的断点。
当我应用下一个优先级(即 ContextIdle)时,我的问题重现 - 我没有到达提到的断点。
请注意,此功能大部分时间都有效,这就是我知道 ContextIdle 优先级是我想要的优先级的方式,因为它确实在大多数情况下将验证应用于输入控件(如果我将优先级降低到后台,它已经没有)。这是因为分配给 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);
}
}
您将在输出中得到以下结果 window:
背景 0
背景 1
背景 2
背景 3
背景 4
背景 5
背景 6
背景 7
背景 8
背景 9
附加背景
上下文空闲
附加后台操作在上下文空闲操作之前执行,即使它在上下文空闲操作之后排入 UI 队列调度程序。这很琐碎,但理解这个概念很重要。
我有一个代码可以检查我是否在 UI 线程上 - 如果是,请立即执行操作。否则,将其放入调度程序队列中。当我将提到的动作 (ExpandFreeDraw) 强制放入 UI 队列时(即使我已经在 UI 线程上),它对我来说都有效:现在动作被调用,我也得到了需要的验证。
我在开发 WPF 应用程序。 我有以下代码:
但是我从来没有到达 ExpandFreeDraw 方法开头的断点:
当我调用 BeginInvoke 方法时,我已经在 UI 线程上:
ExpandFreeDraw 方法也应该发生在 UI 线程上。 由于以下原因,我以上下文空闲优先级调用它:
在 BeginInvoke 行之前,我将 WPF Expander 的 Visibility 从 collapsed 更改为 Visible。它开始呈现它的控件:其中一些控件是输入控件,我想对它们应用验证(通过 AdornerDecorator 完成,这使得输入控件看起来像有一个红色验证边框)。 如果我在更改扩展器的可见性后直接调用 ExpandFreeDraw(只是没有 Dispatcher 的 ExpandFreeDraw()),我会到达 ExpandFreeDraw 方法开头的断点:扩展器可见但装饰器未正确应用 - 没有红色边框效果。
我得到与 Dispatcher.BeginInvoke 相同的效果,下一个较低的优先级,即背景:
在那种情况下,我也到达了 ExpandFreeDraw 方法开头的断点。 当我应用下一个优先级(即 ContextIdle)时,我的问题重现 - 我没有到达提到的断点。
请注意,此功能大部分时间都有效,这就是我知道 ContextIdle 优先级是我想要的优先级的方式,因为它确实在大多数情况下将验证应用于输入控件(如果我将优先级降低到后台,它已经没有)。这是因为分配给 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);
}
}
您将在输出中得到以下结果 window:
背景 0
背景 1
背景 2
背景 3
背景 4
背景 5
背景 6
背景 7
背景 8
背景 9
附加背景
上下文空闲
附加后台操作在上下文空闲操作之前执行,即使它在上下文空闲操作之后排入 UI 队列调度程序。这很琐碎,但理解这个概念很重要。
我有一个代码可以检查我是否在 UI 线程上 - 如果是,请立即执行操作。否则,将其放入调度程序队列中。当我将提到的动作 (ExpandFreeDraw) 强制放入 UI 队列时(即使我已经在 UI 线程上),它对我来说都有效:现在动作被调用,我也得到了需要的验证。