c# - 未显示表单时,如何在不同的线程/任务中处理 Windows.Forms 的初始化?
问题描述
我有一个 C# .NET Framework 4.7 应用程序,其中的主窗体需要一些时间来加载(数据库查询等)。
为了通知用户应用程序正在运行和加载,我实现了一个启动画面。
但是,我无法设法使 MainForm 初始化(数据库查询等)工作。
如果我将初始化代码放入 MainForm 构造函数中,并放入mainForm = new MainForm()
主线程/任务中,由于操作是同步的,因此启动屏幕会冻结,因为没有 DoEvent()。
如果我将初始化代码放入 MainForm 方法中,并mainForm = new MainForm()
如下所示放入,然后将初始化如下所示,我将在InvalidOperationException
尝试访问另一个线程/任务中的组件时以 s 结束。
当我尝试Invoke
在任务中解决此异常时(如下所示),我最终会InvalidOperationException
抱怨在Invoke
未显示表单时无法调用(未创建窗口句柄)。我尝试在调用之前创建窗口句柄Invoke
,但遇到了同样的异常,因为必须显示表单才能显示Invoke
任何内容。
如何在单独的线程/任务中初始化 MainForm,以便多个初始化任务可以在 Main 函数中并行发生?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
internal static class Program
{
[STAThread]
private static int Main()
{
// Display the splash screen.
var splashScreen = new SplashScreenForm()
{
ApplicationTitle = Program.Information.EntryAssembly.Title,
ApplicationVersionInformation = string.Format("Version {0} ({1})", Program.Information.EntryAssembly.InformationalVersion, Program.Information.EntryAssembly.Configuration),
Copyright = Program.Information.EntryAssembly.Copyright
};
splashScreen.Show();
var initTasks = new List<Task>();
var mainForm = new MainForm();
// Load main form.
{
var initTask = new Task(() => { mainForm.Initialize(); });
initTasks.Add(initTask);
initTask.Start();
}
// Some other initialization tasks, that are NOT related to MainForm.
{
var initTask = new Task(() => { Console.WriteLine("Foo Bar") });
initTasks.Add(initTask);
initTask.Start();
}
// Wait until all initialization tasks are done.
while (initTasks.Any((Task t) => { return !Convert.ToBoolean(t.IsCanceled | t.IsFaulted | t.IsCompleted); }))
{
Thread.Sleep(10);
Application.DoEvents();
}
// Check for failed initialization tasks.
if (initTasks.Any((Task t) => { return Convert.ToBoolean(t.IsCanceled | t.IsFaulted); }))
{
var exes = new List<Exception>();
foreach (var t in initTasks.FindAll((Task t) => { return Convert.ToBoolean(t.IsCanceled | t.IsFaulted); }))
{
exes.Add(t.Exception);
}
throw new AggregateException("Some main initialization tasks have failed.", exes.ToArray());
}
// Cleanup tasks.
initTasks.ForEach((Task t) => { t.Dispose(); });
initTasks.Clear();
splashScreen.Close();
splashScreen.Dispose();
Application.Run(mainForm);
Application.Exit();
Application.DoEvents();
return 0;
}
}
解决方案
推荐阅读
- multiple-inheritance - 关于致命钻石问题(多重继承)的问题
- html - Do HTML5 custom elements have any drawbacks compared to classes?
- excel - Can VBA open a document embedded in an Excel workbook
- algorithm - Optimized dijkstra’s algorithm for an extremely dense graph with matrix
- modelica - 如何在 Dymola 中查找哪个组件正在使用外部组件?
- reactjs - How to use custom domain for Serverless app with React frontend?
- html - Problem with creating responsive overlapping Divs
- ruby-on-rails - has_one association with optional: true?
- flutter - 为什么 Flutter 的 SpannableGrid 小部件中的 UI 不刷新以使用 String 流中的最新内容进行更新?
- angular - 角度 http post 错误 415 .net 核心 web api