Sergey Shulik
Sergey Shulik

Reputation: 1010

Dispatcher.BeginInvoke always return DispatcherOperationStatus.Pending status

I try to update ObservableCollection asynchronously using the following code in my WPF project:

if (Dispatcher.Thread != Thread.CurrentThread)
{
    if (Dispatcher.Thread.ThreadState != ThreadState.Stopped && !Dispatcher.Thread.IsBackground)
    {
        Dispatcher.Invoke(new Action(() => { ChangeCollectionByAction(action); }), null);
    }
    else
    {
        var op = Dispatcher.BeginInvoke(new Action(() => { ChangeCollectionByAction(action); }), null);
        var status = op.Status;
        while (status != DispatcherOperationStatus.Completed)
        {
            status = op.Wait(TimeSpan.FromSeconds(1));
        }
    }
}

But unfortunetly status alway equals DispatcherOperationStatus.Pending.

p.s.: may be my problem that i use ElementHost on WinForms project?

Upvotes: 3

Views: 11314

Answers (4)

Cœur
Cœur

Reputation: 38667

Dispatcher.BeginInvoke() is not awaitable.

If .NET 4.5 is available for you, then you can use Dispatcher.InvokeAsync():

if (Dispatcher.Thread != Thread.CurrentThread)
    await Dispatcher.InvokeAsync(() => ChangeCollectionByAction(action));

Upvotes: 1

Rachel
Rachel

Reputation: 132568

If you want something to run once an asynchronous operation is done, you should use it's Completed event.

See this answer for an example

var dispatcherOp = Dispatcher.BeginInvoke( /* your method here */);
dispatcherOp.Completed += (s, e) => { /* callback code here */ };

There's a chance the operation will complete before you subscribe, so you can test the Status property for completion after as well:

if (dispatcherOp.Status == DispatcherOperationStatus.Completed) { ... }

As for the actual problem, I'm not sure without being able to reproduce it. If I had to hazard a guess, it would be that your loop is tying up the current Dispatcher thread, so it can't process the BeginInvoke operation you told it to process, so it will always sit at Pending.

Upvotes: 12

Mareek
Mareek

Reputation: 120

The status of your operation seems to be stale because enum is a value type and you store it in a variable. Changing your code to this should fix your problem :

    var op = Dispatcher.BeginInvoke(new Action(() => { ChangeCollectionByAction(action); }), null);
    while (op.Status!= DispatcherOperationStatus.Completed)
    {
        status = op.Wait(TimeSpan.FromSeconds(1));
    }

In fact you could replace all your code just by this single line:

Dispatcher.BeginInvoke(new Action(() => ChangeCollectionByAction(action))).Wait();

Upvotes: 4

asktomsk
asktomsk

Reputation: 2298

Can you check the Dispatcher.Thread.ThreadState value before call the BeginInvoke?

I think the problem that Dispatcher thread is Stopped. So calling Dispatcher.BeginInvoke in stopped thread will cause infinity Pending status because it can't run anything.

Upvotes: 0

Related Questions