我知道在UI部件上使用多线程是不可取的,但考虑到闪屏界面是应用程序中相当独立的一部分,是否可以通过将其放在其他线程中(可能类似于Chrome的方式),以此来缓解它对性能的影响,这样重要的应用程序部分就可以开始运行了。
.NET框架已经非常好地支持Windows Forms应用程序中的启动画面。请查看这个线程以获取代码示例。它确实针对热启动时间进行了优化,确保在初始化主应用程序之前启动画面和线程。
确保首先加载并显示闪屏窗体,然后在用户查看漂亮的闪屏界面时继续加载你的应用程序。当主窗体加载完成时,在显示自己之前关闭闪屏窗体(一种简单的方法是将闪屏窗体传递给主窗体的构造函数):
static void Main()
{
Application.SetCompatibleTextRenderingDefault(false);
SplashForm splash = new SplashForm();
splash.Show();
splash.Refresh(); // make sure the splash draws itself properly
Application.EnableVisualStyles();
Application.Run(new MainForm(splash));
}
public partial class MainForm : Form
{
SplashForm _splash;
public MainForm(SplashForm splash)
{
_splash = splash;
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
// or do all expensive loading here (or in the constructor if you prefer)
_splash.Close();
}
}
替代方案:如果您不想将闪屏传递给主窗体(可能看起来不太优雅),那么可以订阅主窗体的加载事件,在那里关闭闪屏:
static class Program
{
static SplashForm _splash;
[STAThread]
static void Main()
{
Application.SetCompatibleTextRenderingDefault(false);
_splash = new SplashForm();
_splash.Show();
_splash.Refresh();
Application.EnableVisualStyles();
MainForm mainForm = new MainForm();
mainForm.Load += new EventHandler(mainForm_Load);
Application.Run(mainForm);
}
static void mainForm_Load(object sender, EventArgs e)
{
_splash.Dispose();
}
}
如此线程所述,这种解决方案的潜在缺点是用户无法与启动画面进行交互。然而,通常并不需要这样做。
是的。
你需要创建一个新的STA线程,使用Application.Run
来显示闪屏界面,然后在主线程上主窗体就绪后,使用Invoke
调用Close
。
编辑: 例如:
static SplashForm splash;
Thread splashThread = new Thread(delegate() {
splash = new SplashForm();
Application.Run(splash); //Blocking call on separate thread
});
splashThread.SetApartmentState(ApartmentState.STA)
splashThread.Start();
LoadApp();
//In MainForm_Shown:
splash.BeginInvoke(new Action(splash.Close));
Main
方法显示启动画面,然后调用一个单独的方法来加载应用程序。这样,在显示启动画面之后,所有程序集都将被加载。(当您调用一个方法时,JITter会在方法开始执行之前加载它使用的所有类型)只要所有的UI都留在一个线程上,WinForms中的多线程就可以了。
这就是闪屏通常的做法。重要的工作在后台线程上完成,而闪屏窗口在UI线程上显示,让用户知道程序的其余部分很快就会出现。
在重要的事情发生后,引发一个事件,让UI线程知道是时候隐藏闪屏了(只需记住使用Invoke()将事件处理程序马歇尔回到UI线程以关闭闪屏即可)。
答案实际上与感知有关。有各种方法,如NGEN汇编、将事物放入GAC,但您应该了解的是实际发生了什么。
C#需要时间来加载虚拟机、加载引用的程序集以及根据启动画面上的内容加载程序集。然后,从“冷”启动到启动第一个屏幕还需要一段时间。
这是因为当您首次访问屏幕时正在进行JIT编译。
我使用的策略是传统的轻量级启动页面,它可以快速加载以便可见,但在后台我生成一个线程并加载一个不可见的表单。此表单具有我打算使用的所有控件,因此JIT编译器正在执行其任务并加载程序集。这提供了手法的错觉,使其具有响应性。从启动+可见启动页面+暂停+单击第一个选项所需的时间大于线程执行、清理和卸载表单所需的时间。
否则,应用程序在首次启动时对用户来说会显得笨重和缓慢。屏幕的热启动要快得多,因为程序集和JIT已经完成。