您可以将调用包装RunAsync
在您自己的可以等待的异步方法中,并控制任务的完成,从而自己继续等待调用者。
由于 async-await 以Task
类型为中心,因此您必须使用此类型来编排工作。但是,通常 aTask
将自己安排在线程池线程上运行,因此不能用于安排 UI 工作。
然而,这种TaskCompletionSource
类型的发明是为了充当不定期的傀儡Task
。换句话说,一个TaskCompletionSource
可以创建一个Task
没有计划做任何事情的假人,但通过TaskCompletionSource
可以看起来像正常工作一样运行和完成的方法。
请参阅此示例。
public Task PlayDemoAsync()
{
var completionSource = new TaskCompletionSource<bool>();
this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
try
{
foreach (var ppc in this.Plots.Select(p => this.TransformPlot(p, this.RenderSize)))
{
// For each subsequent stroke plot, we need to start a new figure.
//
if (this.Sketch.DrawingPoints.Any())
this.Sketch.StartNewFigure(ppc.First().Position);
foreach (var point in ppc)
{
await Task.Delay(100);
this.Sketch.DrawingPoints.Add(point.Position);
}
}
completionSource.SetResult(true);
}
catch (Exception e)
{
completionSource.SetException(e);
}
});
return (Task)completionSource.Task;
}
注意:在 UI 线程上完成的主要工作只是每 100 毫秒在屏幕上绘制一些线条。
ATaskCompletionSource
被创建为人偶大师。查看接近尾声,您会看到它有一个Task
返回给调用者的属性。返回Task
满足编译器的需求,并使方法可等待和异步。
然而,这Task
只是一个傀儡,是 UI 线程中实际工作的代理。
看看我如何在那个主 UI 委托中使用该TaskCompletionSource.SetResult
方法将结果强制输入Task
(因为返回给调用者)并传达工作已完成。
如果出现错误,我会使用SetException
“拉另一个字符串”并让它看起来像是 puppet 中出现了异常Task
。
async-await 子系统没有什么不同,因此它可以按您的预期工作。
编辑
正如 svick 所提示的,如果该方法被设计为只能从 UI 线程调用,那么这就足够了:
/// <summary>
/// Begins a demonstration drawing of the asterism.
/// </summary>
public async Task PlayDemoAsync()
{
if (this.Sketch != null)
{
foreach (var ppc in this.Plots.Select(p => this.TransformPlot(p, this.RenderSize)))
{
// For each subsequent stroke plot, we need to start a new figure.
//
if (this.Sketch.DrawingPoints.Any())
this.Sketch.StartNewFigure(ppc.First().Position);
foreach (var point in ppc)
{
await Task.Delay(100);
this.Sketch.DrawingPoints.Add(point.Position);
}
}
}
}