如何在Xamarin表单中启动应用程序期间的进度

时间:2016-07-23 06:16:21

标签: c# xamarin async-await xamarin.forms doevents

我有一个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页宣布长时间运行序列的开始,第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();
}

1 个答案:

答案 0 :(得分: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”的代码放在viewmodel级别,并将标签的内容绑定到viewmodel中的属性,这样你的代码就会更加清晰,而你不必担心线程,我认为

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

await DoStep1Async();