wpfdispatcherbegininvoke

Delegate is never executed while invoked via Dispatcher.BeginInvoke with ContextIdle priority


I work on a WPF application. I have the following code:

enter image description here

But I never get to the breakpoint that is put at the beginning of ExpandFreeDraw method:

enter image description here

When I invoke the BeginInvoke method, I'm already on the UI thread:

enter image description here

The ExpandFreeDraw method should also happen on the UI Thread. I invoke it with priority of context idle for the following reason:

Before the line of BeginInvoke, I change the Visibility of a WPF Expander from collapsed to Visible. It starts rendering its controls: some of those controls are input controls and I want to apply validation to them (done via AdornerDecorator which makes it look like the input control has a red validation border). If I call the ExpandFreeDraw directly after changing the visibility of the Expander (just ExpandFreeDraw() without Dispatcher), I do get to the breakpoint at the beginning of the ExpandFreeDraw method: the expander is visible but the adorner is not applied correctly - no red border effect.

I get the same effect with Dispatcher.BeginInvoke with the next lower priority, which is background:

enter image description here

In that case, I also get to the breakpoint at the beginning of the ExpandFreeDraw method. When I apply the next priority, which is ContextIdle, then my issue is reproduced - I don't get to the mentioned breakpoint.

Note that this functionality works most of the time, and that's how I know the ContextIdle priority is my desired priority, because it does apply the validation to input controls in most of the cases (if I reduce the priority to Background, it already doesn't). That is because the priority given to the Dispatcher is ContextIdle which is lesser that Render - You can read more about it here: http://www.jonathanantoine.com/2011/08/29/update-my-ui-now-how-to-wait-for-the-rendering-to-finish/).

I would like to get some help on how to figure out what is the problem. Why is

enter image description here

invokes the method of ExpandFreeDraw correctly in most of the cases, but in one of the scenarios (which I can't really understand which) it doesn't? How can I debug it?

Maybe:

enter image description here

Could it be that the background operations are never completed? And that's why the operation with ContextIdle priority is never executed? How can I figure it out?


Solution

  • I've finally solved it. My issue was that the UI dispatcher queue kept constantly getting actions with a higher priority (higher than context-idle).

    If you write a code as the following:

    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);
            }
        }
    

    You will get the following result in the output window:

    Background 0
    Background 1
    Background 2
    Background 3
    Background 4
    Background 5
    Background 6
    Background 7
    Background 8
    Background 9
    Additional-Background
    Context-Idle

    Additional-Background action is performed before the context-idle action, even though it was queued into the UI queue dispatcher after the context-idle action. It's trivial, but it is important to understand this concept.

    I had a code that checks if I'm on the UI thread - If so, perform the action immediately. Otherwise, queue it into the dispatcher queue. When I forced the mentioned action (ExpandFreeDraw) into the UI queue (even if I was already on the UI thread), it all worked for me: now the action is invoked and I also get the needed validation.