You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加闪屏后C# WinForms中Main()的Task.WaitAll为何挂起?

解决WinForms闪屏与Squirrel更新任务阻塞的问题

嘿,这个问题我之前也碰到过,核心原因其实是UI线程阻塞导致的死锁。WinForms是单线程模型,你的Main方法运行在UI线程上:当你显示闪屏后调用Task.WaitAll,会直接阻塞UI线程——而如果Squirrel的更新操作内部需要调度回UI线程(比如某些状态通知、弹窗),就会因为UI线程被卡死而永远等不到任务完成,自然就一直卡着了。

下面给你两个靠谱的解决方案,优先推荐第一个:

方案一:使用异步Main方法(推荐)

从C# 7.1开始,WinForms支持异步入口方法,这是最优雅的解决方式。把static void Main()改成async static Task Main(),用await替代Task.WaitAll,这样UI线程在等待更新任务时不会被阻塞,还能正常处理闪屏的绘制和消息循环。

示例代码:

using System;
using System.Threading.Tasks;
using System.Windows.Forms;
using Squirrel;

namespace YourAppNamespace
{
    static class Program
    {
        // 改成异步Main
        [STAThread]
        async static Task Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            // 显示闪屏
            var splashForm = new SplashForm();
            splashForm.Show();

            try
            {
                // 异步等待更新任务完成,UI线程不阻塞
                await CheckForUpdatesAsync();
            }
            catch (Exception ex)
            {
                // 处理更新异常,比如提示用户
                MessageBox.Show($"更新检查失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                // 关闭闪屏,启动主窗体
                splashForm.Close();
                Application.Run(new MainForm());
            }
        }

        private static async Task CheckForUpdatesAsync()
        {
            using var updateManager = await UpdateManager.GitHubUpdateManager("https://your-repo-url");
            var updateInfo = await updateManager.CheckForUpdate();
            if (updateInfo.ReleasesToApply.Any())
            {
                await updateManager.UpdateApp();
                // 更新完成后可以重启应用,Squirrel有自带方法
                UpdateManager.RestartApp();
            }
        }
    }
}

关键说明:

  • await会让UI线程在等待期间释放出来处理闪屏的消息,既保证闪屏正常显示,又能让更新任务顺利执行。
  • 记得加上[STAThread]特性,WinForms入口必须有这个。

方案二:后台线程执行更新(兼容旧版本C#)

如果你的项目用的是不支持异步Main的旧版C#,可以把更新任务放到后台线程,同时在等待期间主动处理闪屏的UI消息(不推荐长期用,但应急没问题):

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Squirrel;

namespace YourAppNamespace
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            var splashForm = new SplashForm();
            splashForm.Show();

            // 把更新任务丢到后台线程
            var updateTask = Task.Run(async () => await CheckForUpdatesAsync());

            // 等待期间处理闪屏的UI消息,避免界面假死
            while (!updateTask.IsCompleted)
            {
                Application.DoEvents();
                Thread.Sleep(50); // 降低CPU占用
            }

            // 处理任务异常
            try
            {
                updateTask.Wait();
            }
            catch (AggregateException ex)
            {
                MessageBox.Show($"更新检查失败:{ex.InnerException?.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            splashForm.Close();
            Application.Run(new MainForm());
        }

        private static async Task CheckForUpdatesAsync()
        {
            using var updateManager = await UpdateManager.GitHubUpdateManager("https://your-repo-url");
            var updateInfo = await updateManager.CheckForUpdate();
            if (updateInfo.ReleasesToApply.Any())
            {
                await updateManager.UpdateApp();
                UpdateManager.RestartApp();
            }
        }
    }
}

注意:Application.DoEvents()虽然能让闪屏动起来,但可能引入意外的UI交互问题(比如用户不小心点击闪屏触发事件),所以优先用方案一。

额外小建议

  • 把闪屏设置为TopMost = true,避免被其他窗口遮挡,提升用户体验。
  • 在闪屏上可以加个进度条或文字提示,比如“正在检查更新...”,让用户知道程序在运行。

内容的提问来源于stack exchange,提问作者afarley

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:25:23