在等待 Dispatcher.RunAsync
时,继续会在工作安排时发生,而不是在工作完成时发生。我如何等待工作完成?
编辑
我最初的问题假设过早继续是由 API 的设计引起的,所以这是真正的问题。
当使用异步委托(delegate)等待 Dispatcher.RunAsync
时,在委托(delegate)代码中使用 await
时,遇到 await
时会继续,不是在工作完成时。我如何等待工作完成?
编辑 2
您可能需要分派(dispatch)已在 UI 线程上的工作的一个原因是解决微妙的时间和布局问题。视觉树中元素的大小和位置的值不断变化是很常见的,为 UI 的后续迭代安排工作会有所帮助。
最佳答案
我在 Microsoft github repository 上找到了以下建议: 如何await a UI task sent from a background thread .
设置
为 CoreDispatcher
定义这个扩展方法:
using System;
using System.Threading.Tasks;
using Windows.UI.Core;
public static class DispatcherTaskExtensions
{
public static async Task<T> RunTaskAsync<T>(this CoreDispatcher dispatcher,
Func<Task<T>> func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal)
{
var taskCompletionSource = new TaskCompletionSource<T>();
await dispatcher.RunAsync(priority, async () =>
{
try
{
taskCompletionSource.SetResult(await func());
}
catch (Exception ex)
{
taskCompletionSource.SetException(ex);
}
});
return await taskCompletionSource.Task;
}
// There is no TaskCompletionSource<void> so we use a bool that we throw away.
public static async Task RunTaskAsync(this CoreDispatcher dispatcher,
Func<Task> func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) =>
await RunTaskAsync(dispatcher, async () => { await func(); return false; }, priority);
}
完成后,您需要做的就是使用新的 RunTaskAsync
方法让您的后台任务等待 UI 工作。
使用示例
假设这是需要在 UI 线程中运行的方法。注意调试语句,这将有助于遵循流程:
public static async Task<string> ShowMessageAsync()
{
// Set up a MessageDialog
var popup = new Windows.UI.Popups.MessageDialog("Question", "Please pick a button to continue");
popup.Commands.Add(new Windows.UI.Popups.UICommand("Button 1"));
popup.Commands.Add(new Windows.UI.Popups.UICommand("Button 2"));
popup.CancelCommandIndex = 0;
// About to show the dialog
Debug.WriteLine("Waiting for user choice...");
var command = await popup.ShowAsync();
// Dialog has been dismissed by the user
Debug.WriteLine("User has made a choice. Returning result.");
return command.Label;
}
要从您的后台线程等待它,这就是您使用 RunTaskAsync
的方式:
// Background thread calls this method
public async void Object_Callback()
{
Debug.WriteLine("Object_Callback() has been called.");
// Do the UI work, and await for it to complete before continuing execution
var buttonLabel = await Dispatcher.RunTaskAsync(ShowMessageAsync);
Debug.WriteLine($"Object_Callback() is running again. User clicked {buttonLabel}.");
}
然后输出看起来像这样:
Object_Callback() has been called.
Waiting for user choice...
User has made a choice. Returning result.
Object_Callback() is running again. User clicked Button 1.
关于c# - RunAsync - 如何等待 UI 线程上的工作完成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19133660/