我尝试使用WPF项目中的以下代码异步更新ObservableCollection
:
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));
}
}
}
但不幸的状态总是等于DispatcherOperationStatus.Pending
。
p.s:可能是我在WinForms项目中使用ElementHost的问题?
答案 0 :(得分:13)
如果您希望在异步操作完成后运行某些内容,则应使用它的Completed
事件。
请参阅this答案以获取示例
var dispatcherOp = Dispatcher.BeginInvoke( /* your method here */); dispatcherOp.Completed += (s, e) => { /* callback code here */ };
在您订阅之前,操作有可能完成,所以 你也可以测试Status属性是否完成:
if (dispatcherOp.Status == DispatcherOperationStatus.Completed) { ... }
至于实际问题,我不确定无法重现它。如果我不得不冒险猜测,那就是你的循环会占用当前的Dispatcher
线程,因此它无法处理你告诉它处理的BeginInvoke
操作,所以它总会坐着在Pending
。
答案 1 :(得分:4)
您的操作状态似乎已过时,因为枚举是一种值类型,您将其存储在变量中。 将代码更改为此可以解决您的问题:
var op = Dispatcher.BeginInvoke(new Action(() => { ChangeCollectionByAction(action); }), null);
while (op.Status!= DispatcherOperationStatus.Completed)
{
status = op.Wait(TimeSpan.FromSeconds(1));
}
事实上,您可以通过以下一行替换所有代码:
Dispatcher.BeginInvoke(new Action(() => ChangeCollectionByAction(action))).Wait();
答案 2 :(得分:1)
Dispatcher.BeginInvoke()
无法等待。
如果您可以使用.NET 4.5,则可以使用Dispatcher.InvokeAsync()
:
if (Dispatcher.Thread != Thread.CurrentThread)
await Dispatcher.InvokeAsync(() => ChangeCollectionByAction(action));
答案 3 :(得分:0)
您可以在致电Dispatcher.Thread.ThreadState
之前检查BeginInvoke
值吗?
我认为Dispatcher线程已停止的问题。因此,在已停止的线程中调用Dispatcher.BeginInvoke
将导致无限等待状态,因为它无法运行任何内容。