为什么在设置 MainPage 属性 之前等待 App.OnStart() 不加载主页

Why awaiting in App.OnStart() before setting the MainPage property doesn't load main page

首先,我知道文档指出我应该在 App class 构造函数 (https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/application-class#mainpage-property) 中设置 MainPage 属性。

为了简化,我需要做的是在 OnStart() 事件处理程序中进行一些异步操作,然后设置 MainPage 属性。这个问题想触及框架本身的根本问题。

类似这样的东西(在一个空白的Xamarin.Forms项目上简化,如果你想试试):

public partial class App : Application
{

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

    protected override async void OnStart()
    {
        //Uncomenting the following line makes the page be shown
        //MainPage = new Page() { BackgroundColor = Color.Red };
        
        //Simulate some fast async work. If you comment this line the MainPage will be shown just fine
        await Task.Delay(100);

        //The page is never displayed to the user unless first commented line in this method is uncommented
        MainPage = new Page(){ BackgroundColor = Color.Red };
    }
}

如果您只是不等待任何事情并同步执行所有代码,则 MainPage 设置正确,但如果我等待任何任务则不会。为什么?

作为对原始 SynchronizationContext 的 await Task.Delay(100) 调用 returns(我假设将在 UI 线程上),我认为这不是问题所在。

非常感谢!

如您所见,OnStart returns 无效,而不是 Task,因此它不是异步的。你做到了 async void 但调用者(调用 OnStart 的框架代码)无法等待异步操作完成。对于调用者,OnStartawait Task.Delay 命中时(即 OnStart returns 时)立即完成,因此它会继续执行其他操作。当 await Task.Delay 完成并且您设置 MainPage - 您实际上并未处于初始化过程的 OnStart 阶段,该阶段已经在 100 毫秒前完成。

考虑这个应该澄清它的例子:

public class Program
{
    public static void Main()
    {
        var app = new Application();
        app.Start();
    }
}

class Application
{
    public string MainPage { get; set; }
    protected virtual void OnStart()
    {

    }

    public void Start()
    {
        Console.WriteLine("calling OnStart");
        // can't await or anything here, it returns void
        OnStart();

        Console.WriteLine("OnStart called");
        // now we consider initialization is done and check MainPage
        if (MainPage != null)
        {
            Console.WriteLine(MainPage);
        }
        Console.WriteLine("Initialization done");
    }
}

class MyApplication : Application
{
    protected override async void OnStart()
    {
        await Task.Delay(100);
        // we set MainPage but it's too late
        MainPage = "Hello";
    }
}