如何在 Xamarin Forms 中的应用程序启动期间显示进度

How to show progress during app startup in Xamarin Forms

我有一个 Xamarin Forms 应用程序需要在启动期间执行一系列长 运行 操作。我想通知用户进度,使用带有简单状态消息的页面,该消息会随着序列的进行而变化。

操作序列作为一组异步方法实现,我将其包装在一个异步容器方法中,该方法还包含更新 UI 的代码。这是一个简化版本:

private async Task DoStartupSequence()
{
    SetStatusMessage("Step 1");
    await DoStep1();
    SetStatusMessage("Step 2");
    await DoStep2();
    SetStatusMessage("Step 3");
    await DoStep3();
    SetStatusMessage("Completed");
}

但是,无论我如何调用序列,UI 都不会更新,直到序列执行完成。

我已经在 App 构造函数中尝试 运行 在它自己的线程上的序列:

public App()
{
    InitializeComponent();
    Task.Run(() => DoStartupSequence()).Wait();
}

我还尝试从 OnStart 方法中异步调用序列:

protected override async void OnStart()
{
    await DoStartupSequence();
}

在 WinForms 应用程序中,可以使用 Application.DoEvents 解决此问题(尽管我知道这种方法有其自身的问题)。无论如何,Xamarin Forms 似乎不支持这样的东西。

这似乎是一个常见的要求,我认为必须有一个标准模式来实现它。有人知道是什么吗?

非常感谢,

蒂姆

更新:响应@BraveHeart 的建议,我能够进一步简化我的测试代码以显示无法正常工作的地方。

以下示例引用了 2 个静态页面,每个页面仅包含一个标签。第一页宣布长 运行 序列的开始,第二页宣布其完成。我的目标是看到这两个页面在第一页和第二页之间延迟 1 秒呈现。实际上,我从来没有看到第 1 页,因为这两个页面是一起呈现的。

public App()
{
    InitializeComponent();

    var navigationPage = new NavigationPage();

    MainPage = navigationPage;

    navigationPage.Navigation.PushAsync(new TestPage1(), false).Wait();

    Task.Delay(1000).Wait();

    navigationPage.Navigation.PushAsync(new TestPage2(), false).Wait();
}

UI 中的更改只能通过 UI 线程进行。

public App()
{
    InitializeComponent();
    Task.Run(() => DoStartupSequence()).Wait();
}

这里的这段代码告诉程序创建另一个任务(线程)来执行 DoStartupSequence() 包括 SetStatusMessage() 其中我假设它只是设置了标签的内容或类似的内容,并且 DOES NOT 中有其他等待的内容。

所以试着把它变成这样

public App()
{
    InitializeComponent();
    StartupSequence(); 
}

private async void StartupSequence()
{
    SetStatusMessage("Step 1");
    await DoStep1();
    SetStatusMessage("Step 2");
    await DoStep2();
    SetStatusMessage("Step 3");
    await DoStep3();
    SetStatusMessage("Completed");
}

我认为这可以解决您的问题。不过,我的建议是把"DoSteps"的代码放在viewmodel层,这样把label的内容绑定到viewmodel里的一个属性你后面的代码会更干净,你不必担心线程,我认为

我注意到的另一点是命名约定。简而言之,任何等待等待的东西都应该有一个名称+"Async" 作为后缀,所以它将是

await DoStep1Async();