[英]await inside a WPF Dispatcher call
What is the best solution to ensure errorhandling when awating inside a delegate that is pased to the dispatcher?在传递给调度程序的委托中确保错误处理的最佳解决方案是什么?
In short: I need to return a number after parsing a calculation to Foo.简而言之:我需要在将计算解析为 Foo 后返回一个数字。 That calculation is very slow and have to be done on the UI thread.
该计算非常缓慢,必须在 UI 线程上完成。 The calculation must be handed to another class as a
Task<string>
.计算必须作为
Task<string>
交给另一个类。
The only solution I could come up with was CallFooWithATask___3 - and not even sure about that..我能想出的唯一解决方案是 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");
}
You're pretty close.你很接近。 Just extract your async code in a method or in a
Func<Task<string>>
to avoid ending with an async void
:只需在方法或
Func<Task<string>>
提取异步代码,以避免以async void
结尾:
Func<Task<string>> func = async () =>
{
var a = await GetWithSideEffects();
return a;
};
Then invoke it with InvokeAsync
.然后使用
InvokeAsync
调用它。 You'll end up with a Task<Task<string>>
.你最终会得到一个
Task<Task<string>>
。 The inner task is the one returned by your async method, the outer task is the one generated by InvokeAsync
to indicate when the call is actually dispatched.内部任务是异步方法返回的任务,外部任务是
InvokeAsync
生成的InvokeAsync
用于指示实际调度调用的时间。 Use .Unwrap
to merge those tasks, and finally send them to your other method:使用
.Unwrap
合并这些任务,最后将它们发送到你的另一个方法:
var task = Dispatcher.InvokeAsync(func).Task.Unwrap();
foo.CallMeWithATaskThatIsFinishedWhenTheUIIsUpdated(task);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.