在WPF Dispatcher调用中等待



在传递给调度程序的委托内部发出警告时,确保错误处理的最佳解决方案是什么?

简而言之:我需要在解析一个计算后返回一个数字给Foo。这种计算非常缓慢,必须在UI线程上完成。计算必须作为Task<string>交给另一个类。

我能想到的唯一解决方案是CallFooWithATask___3,对此我甚至不确定。。

public class Foo
{
public void CallMeWithATaskThatIsFinishedWhenTheUIIsUpdated(Task<string> task) { }
}
// CallFooWithATask___ is invoked from unknown thread. Can't wait for GetWithSideEffects on calling thread
public class SomeClass
{
private TextBox textBox;
public int CallFooWithATask___1(Foo foo)
{
// not good - async void -> no error handling
var tcs = new TaskCompletionSource<string>();
Dispatcher.CurrentDispatcher.BeginInvoke(async () =>
{                
var a = await GetWithSideEffects();
textBox.Text = a;
tcs.SetResult(a);
});
// quite fast - probally put it in a queue and returns
foo.CallMeWithATaskThatIsFinishedWhenTheUIIsUpdated(tcs.Task);
return 1;
}
public async Task<int> CallFooWithATask___2(Foo foo)
{
// not good - still async void  -> no error handling .. when is foo actually called? I assume when hitting the inner await'ish?
var task =  await Dispatcher.CurrentDispatcher.InvokeAsync(async () =>
{
var a = await GetWithSideEffects();
textBox.Text = a;
return a;
});
// quite fast - probally put it in a queue and returns
foo.CallMeWithATaskThatIsFinishedWhenTheUIIsUpdated(task);
return 1;
}
public int CallFooWithATask___3(Foo foo)
{
// what is the elegant solution - probally not this?
var tcs = new TaskCompletionSource<string>();
Dispatcher.CurrentDispatcher.BeginInvoke(async () =>
{
try
{
var a = await GetWithSideEffects();
textBox.Text = a;
tcs.SetResult(a);
}
catch (Exception ex) { tcs.SetException(ex); }
});
// quite fast - probally put it in a queue and returns
foo.CallMeWithATaskThatIsFinishedWhenTheUIIsUpdated(tcs.Task);
return 1;
}
// this might trigger ui updates and is very slow ..
private Task<string> GetWithSideEffects()=> Task.FromResult("42");
}

您非常接近。只需在方法或Func<Task<string>>中提取异步代码,即可避免以async void:结束

Func<Task<string>> func = async () =>
{
var a = await GetWithSideEffects();
return a;
};

然后用InvokeAsync调用它。你最终会得到一个Task<Task<string>>。内部任务是异步方法返回的任务,外部任务是InvokeAsync生成的任务,用于指示实际调度调用的时间。使用.Unwrap合并这些任务,并最终将它们发送到您的另一种方法:

var task = Dispatcher.InvokeAsync(func).Task.Unwrap();
foo.CallMeWithATaskThatIsFinishedWhenTheUIIsUpdated(task);

最新更新