c# - RunAsync - 如何等待 UI 线程上的工作完成?

标签 c# windows-runtime windows-store-apps async-await

在等待 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/

相关文章:

c# - 如何捕获包含在我的以下代码中的 WINDOWS 用户名?

c# - 可以将 IQueryable<Derived> 转换为 IQueryable<Base> 吗?

c# - 在 WPF 事件中同时运行两个代码部分的推荐方法?

c++ - 如何为 IAsyncOperation 指定回调方法

c# - 在我的后台任务中查找辅助磁贴失败,代码为 1

c# - 将字符串转换为页面类型?

windows - 我可以禁用Win10 S模式支持以通过Windows应用商店审查吗?

c# - 通过 Func<> 传递参数

C#/XAML winRT 应用导出 PDF

c# - 如何从 C++ 后台任务(Windows 通用应用程序)调用 C# 函数?