通过具有 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 线程上),它对我来说都有效:现在动作被调用,我也得到了需要的验证。