Reputation: 1010
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
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
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
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
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