1.需要添加对Microsoft.VisualBasic 引用,
2.准备frmMain,frmSplash两个窗口
说明:
frmSplash在主线程上建立,但是在独立线程上进行消息循环
当protected override void OnCreateMainForm 方法执行完毕,会隐藏frmSplash
可以在OnCreateMainForm中执行预加载操作,或者在frmMain的构造里执行,不要在frmMain的OnLoad事件中进行
当需要改边frmSplash窗体上控件属性时(如显示加载提示等)需要使用控件的Invoke
using System; using System.Collections.Generic; using System.Windows.Forms; namespace SplashLoader { static class Program { /// <summary> /// 应用程序的主入口点。 /// </summary> [STAThread] static void Main(String[] args) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); new SplashApp().Run(args); } } }
using System; using System.Collections.Generic; using System.Text; using Microsoft.VisualBasic.ApplicationServices; using System.Diagnostics; using System.Windows.Forms; using System.IO; using System.Threading; using System.Reflection; using System.Configuration; using ISplashLoader; namespace SplashLoader { public class SplashApp : WindowsFormsApplicationBase { private frmSplash _frmSplash = null; protected override void OnCreateSplashScreen() { //在主UI线程上运行 Console.WriteLine("OnCreateSplashScreen:" + Thread.CurrentThread.ManagedThreadId); //这里调用是在主线程上的 //但是SplashForm的消息循环是在独立线程上的 //可以在SplashForm的OnLoad事件中看到是一个独立的线程 //因此OnCreateMainForm即使阻塞了,SplashForm也能正常绘制 //可以把数据初试化操作放在frmMain的构造函数中 //但是不要放在OnLoad事件中,因为在OnLoad时UI界面已经绘制完成 //如果在里面放置一些阻塞型的操作会导致界面卡死 //SplashForm在frmMain的OnLoad调用时隐藏(没有发现调用close事件--会有短暂延迟) // _frmSplash = new frmSplash(); SplashScreen = _frmSplash; SplashScreen.ShowInTaskbar = false; SplashScreen.Cursor = System.Windows.Forms.Cursors.AppStarting; } private bool CheckUpgrade() { if (this.CommandLineArgs.Count > 0) { if (string.Compare(CommandLineArgs[0], "Upgrade:Skip", true) == 0) { return false; } } return true; } protected override void OnCreateMainForm() { try { //在主UI线程上运行 Console.WriteLine("OnCreateMainForm:" + Thread.CurrentThread.ManagedThreadId); //注意使用SplashForm 后,可以在主窗体的构造中加载数据 //或者在SplashApp的OnCreateMainForm()中,不要放在frmMain的OnLoad事件中 if (CheckUpgrade()) { _frmSplash.SetTips("检测是否有新的版本..."); Process pa = new Process(); pa.StartInfo.UseShellExecute = false; pa.StartInfo.FileName = Path.Combine(Application.StartupPath, @"UpdateApp.exe"); pa.StartInfo.Arguments = "AppStart"; pa.Start(); while (!pa.HasExited) ; } String assembley = ConfigurationManager.AppSettings["MainAssembly"]; String type = ConfigurationManager.AppSettings["MainForm"]; MainForm = CreateForm(assembley, type, _frmSplash); } catch (Exception e) { //处理动态加载过程中的异常 MessageBox.Show(e.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } /// <summary> /// 动太加载窗体 /// </summary> /// <param name="assembly">如:FIStudio.WinUI.(exe|dll)</param> /// <param name="type">FIStudio.WinUI.UI.frmCooperatorMgr</param> /// <returns></returns> private Form CreateForm(String assembly,String type,ILoadTips loadTips) { String a = System.IO.Path.GetFileNameWithoutExtension(assembly); Type t = Assembly.Load(a).GetType(type, true); Form frm = Activator.CreateInstance(t, new Object[] { loadTips }) as Form; return frm; } } }
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Threading; using ISplashLoader; namespace SplashLoader { public partial class frmSplash : Form ,ILoadTips { public frmSplash() { InitializeComponent(); BackgroundImageLayout = ImageLayout.Stretch; FormBorderStyle = FormBorderStyle.None; StartPosition = FormStartPosition.CenterScreen; Console.WriteLine("SplashForm:" + Thread.CurrentThread.ManagedThreadId); } delegate void SetTipsHandle(String tips); public void SetTips(String tips) { if (lblTips.InvokeRequired) { lblTips.Invoke(new SetTipsHandle(SetTips), tips); } else { lblTips.Text = tips; } } private void frmSplash_Load(object sender, EventArgs e) { Console.WriteLine("SplashForm_Load:" + Thread.CurrentThread.ManagedThreadId); } } }
Demo:参考华为网盘/软件测试与任务/引导窗体