首页 > 解决方案 > Xamarin:如何在 UI 线程上执行长时间运行的操作时让 UI 重绘(不使用 async/await)

问题描述

我(出于某种原因)被迫在我的 xamarin 表单(NetStandard)应用程序的 UI 线程上执行长时间运行的操作。在此操作期间,我想更新 UI 以向用户提供进度反馈。我可以更改 UI,但 UI 不会重绘,因为我无法使用 await/async 将指令指针返回给操作系统。

有什么方法可以在不使用 async/await 的情况下处理 UI 线程上的消息。在旧的 Win32 日子里,我认为 Translate/DispatchMessage 可用于保持消息泵在长时间运行的操作中运行,这与我需要的类似。

背景:我有一个由运行在我的 UI 线程上的 android 操作系统定义和调用的接口。重要的是,我们从该服务返回此长时间运行的操作的结果。因为接口未定义为异步,所以我不能使用 await 让 IP 返回操作系统。如果我这样做了,该函数将立即返回(不获取结果)并继续执行(即,它会失败)。我无法改变这些情况。

// The following class is called directly by the AndroidOS
class CloudHostCardService : HostApduService
{
    // The following method is called by the AndroidOS on the UI thread
    public override byte[] ProcessCommandApdu(byte[] commandApdu, Bundle extras)
    {
        ViewModels.MainPageViewModel.SetStatus("Processing Cmd");  // <-- updates UI
        return processor.ProcessCommand(commandApdu); // <-- Long running operation
    }
}

有没有其他方法可以触发重绘(Win32 中的泵消息)?

标签: androidmultithreadingxamarin.net-standardui-thread

解决方案


nullHostApduService 允许您从返回ProcessCommandApdu,然后使用 SendResponseApdu 来提供ResponseApdu.

此方法在应用程序的主线程上运行。如果不能立即返回响应 APDU,则返回 null 并稍后使用 sendResponseApdu(byte[]) 方法。

例子:

public class SampleHostApduService : HostApduService
{
    public override void OnDeactivated([GeneratedEnum] DeactivationReason reason)
    {
    }

    public override byte[] ProcessCommandApdu(byte[] commandApdu, Bundle extras)
    {
        // Update your UI via your viewmodel.

        // Fire and forget
        Task.Run(() => {
            this.SendResponseApdu(processor.ProcessCommand(commandApdu));
         });

        // Return null as we handle this using SendResponseApdu
        return null;
    }
}

推荐阅读