WPF应用程序,在打开窗口之前运行异步任务

2024-05-11

我遇到了一个问题,我需要在主窗口打开并显示之前运行异步任务。 IE。

[STAThread]
static void Main(string[] args)
     MainWindow window = new MainWindow();

     SplashScreen.Show("Authenticating");
     await Authenticate();  // Need something similar to this....
     SplashScreen.Close();

     new Application().Run(window);
}

static async Task Authenticate()
{
     // Load Local Auth Data
     var result = await Authenticator.Authenticate(); // Validates google token with webservice
     if (result.GoogleReauthRequired)
     {
         if (MessageBox.Show(......) == MessageBoxResult.Yes)
         {
              Google.Reauthenticate();// Opens web browser for account to be logged into using OAuth
              result = await Authenticator.Authenticate();
         }
     }
     // Initialize state
}

不幸的是,由于启动Main函数不是异步的(而且不可能是因为它是STAThread)。我不能像上图那样简单地做到这一点。

我尝试了其他几种方法,例如:

        MainWindow window = new MainWindow();

        SplashScreen.Show("Authenticating");
        Authenticate().Wait();
        SplashScreen.Close();

        new Application().Run(window);

但这不起作用,因为身份验证代码使用 async/await 发出 Web 请求,因此将是自阻塞的,因为它永远无法重新进入同步上下文。

因此,为了解决这个问题,您最初会想到将其添加到任务中,如下所示:

        MainWindow window = new MainWindow();

        SplashScreen.Show("Authenticating");
        Task.Run(async () => await Authenticate()).Wait();
        SplashScreen.Close();

        new Application().Run(window);

但这也失败了,因为身份验证方法可能会打开一个消息框,这要求它位于主线程而不是工作线程上。

我的第三次尝试也导致了问题,我尝试了最小化窗口、从任务栏删除、将可见性设置为隐藏/折叠等多种变体和组合

        MainWindow window = new MainWindow();
        // Visibility attempts

        window.Loaded += async (a, b) =>
        {
               await Authentication();
               // Undoing the above visibility attempts
               SplashScreen.Close();
        };

        SplashScreen.Show("Authenticating");

        new Application().Run(window);

使用这种方法,不会出现死锁,但是在初始化代码完成之前窗口就被渲染并可访问(即身份验证/验证),这也是不可取的。

显然,上面的代码已被简化,足以显示我的问题。

所以我的问题是如何在窗口对客户端可见之前运行此异步方法。

我知道可以选择在身份验证完成之前仅在窗口中显示加载屏幕,但我的启动屏幕非常美观,我更愿意使用它。


您可以在 Main 方法中执行这些操作,而不是在OnStartup您的申请方法(内App.xaml.cs)。只需确保标记OnStartup方法与async修改器并删除StartupUri从您的应用程序定义中App.xaml.

Example App.xaml.cs:

namespace WpfApp1
{
    public partial class App : Application
    {
        protected override async void OnStartup(StartupEventArgs e)
        {
            SplashScreen.Show("Authenticating");
            await Authenticate();
            SplashScreen.Close();

            MainWindow = new MainWindow();
            MainWindow.Show();
        }
    }
}

Example App.xaml: (no StartupUri属性)

<Application x:Class="WpfApp1.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    >
</Application>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

WPF应用程序,在打开窗口之前运行异步任务 的相关文章

随机推荐