如何在 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();
我有一个 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();