1

我有一个 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();
}
4

1 回答 1

2

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

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

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

所以试着让它像这样

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”的代码放在视图模型级别,并将标签的内容绑定到视图模型中的属性,这样你的代码会更干净,你不必担心线程,我想

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

await DoStep1Async();
于 2016-07-23T09:38:08.893 回答