标签:
Windows Form经常会在启动主界面的时候预先有启动画面,这也是因为用户体验的需要,用户知道已经启动application,而不是在load resource的时候等待。因此这里不能用单线程的思路,单单只是设计一个界面而已,而需要在splash画面的时候同时Load resource。那么这个技术有两个线程,一个是splash画面,二是load resource。搜了一些资料,下面进行一些总结:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Windows.Forms; 5 using System.Threading; 6 7 namespace WindowsTest 8 { 9 static class Program 10 { 11 /// <summary> 12 /// 应用程序的主入口点。 13 /// </summary> 14 [STAThread] 15 static void Main() 16 { 17 Application.EnableVisualStyles(); 18 Application.SetCompatibleTextRenderingDefault(false); 19 20 Thread thUI = new Thread(new ThreadStart(ShowSplashWindow)); 21 thUI.Name = "Splash UI"; 22 thUI.Priority = ThreadPriority.Normal; 23 thUI.Start(); 24 25 Thread th = new Thread(new ThreadStart(LoadResources)); 26 th.Name = "Resource Loader"; 27 //th.Priority = ThreadPriority.Highest; 28 th.Priority = ThreadPriority.Normal; 29 th.Start(); 30 th.Join(); 31 32 if (splashForm != null) 33 { 34 splashForm.Invoke(new MethodInvoker(delegate { splashForm.Close(); })); 35 } 36 37 thUI.Join(); 38 Application.Run(new MainForm()); 39 } 40 41 public static SplashForm splashForm 42 { 43 get; 44 set; 45 } 46 47 private static void ShowSplashWindow() 48 { 49 splashForm = new SplashForm(); 50 Application.Run(splashForm); 51 } 52 53 private static void LoadResources() 54 { 55 for (int i = 1; i <= 8; i++) 56 { 57 if (splashForm != null) 58 { 59 splashForm.Invoke(new MethodInvoker(delegate { splashForm.label1.Text = "Loading some things... " + DateTime.Now.ToString(); })); 60 } 61 Thread.Sleep(1000); 62 } 63 splashForm.Invoke(new MethodInvoker(delegate { splashForm.label1.Text = "Done. " + DateTime.Now.ToString(); })); 64 } 65 } 66 }
这段代码的问题在于画面启动完主界面是最小化了,不解为何如此
http://www.sufeinet.com/forum.php?mod=viewthread&action=printable&tid=2697
这里的代码比较成熟了,我做了一些小小的改变。用ApplicationContext来解决splash form和main form之间的转换,而在Program的类的InitApp function里如果要改变splash from的label1则需要Invoke来异步调用SplashFrom的PrintMsg function,否则会卡卡面。
Program.cs:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Windows.Forms; 5 using System.Threading; 6 7 namespace WindowsTest 8 { 9 static class Program 10 { 11 /// <summary> 12 /// 应用程序的主入口点。 13 /// </summary> 14 [STAThread] 15 static void Main() 16 { 17 Application.EnableVisualStyles(); 18 Application.SetCompatibleTextRenderingDefault(false); 19 20 MyApplicationContent appContent = new MyApplicationContent(new MainForm(), new SplashForm()); 21 Application.Run(appContent); 22 } 23 24 //模拟耗时操作,这里假调程序需要访问网络来实现登录验证 25 //这是一个耗时操作,我们需要在执行的过程中,向用户实时显示一些信息 26 //那么,多线程是唯一的解决方案,在主线程执行这些,界面会死掉的 27 public static void InitApp(Object parm) 28 { 29 SplashForm startup = parm as SplashForm; 30 startup.Invoke(new UiThreadProc(startup.PrintMsg), "正在初始化..."); 31 Thread.Sleep(100); 32 startup.Invoke(new UiThreadProc(startup.PrintMsg), "正在验证用户身份信息..."); 33 Thread.Sleep(2000); 34 startup.Invoke(new UiThreadProc(startup.PrintMsg), "用户身份验证成功。"); 35 Thread.Sleep(500); 36 startup.Invoke(new UiThreadProc(startup.PrintMsg), "正在登录..."); 37 Thread.Sleep(2000); 38 bool loginSuccess = true; 39 //这里可以根据执行的结果判断,如果登录失败就退出程序,否则显示主窗体 40 if (loginSuccess) 41 { 42 startup.Invoke(new UiThreadProc(startup.PrintMsg), "登录成功,欢迎使用!"); 43 Thread.Sleep(100); 44 startup.Invoke(new UiThreadProc(startup.CloseForm), false); 45 } 46 else 47 { 48 startup.Invoke(new UiThreadProc(startup.CloseForm), true); 49 } 50 } 51 } 52 53 public delegate void UiThreadProc(Object o); 54 //WinForm里,默认第一个创建的窗体是主窗体,所以需要用应用程序域来管理 55 public class MyApplicationContent : ApplicationContext 56 { 57 private Form realMainForm; 58 59 public MyApplicationContent(Form mainForm, Form flashForm) 60 : base(mainForm) 61 { 62 this.realMainForm = mainForm; 63 this.MainForm = flashForm; 64 } 65 66 protected override void OnMainFormClosed(object sender, EventArgs e) 67 { 68 if (sender is SplashForm) 69 { 70 SplashForm splashForm = sender as SplashForm; 71 72 if (!splashForm.Exit) 73 { 74 this.MainForm = realMainForm; 75 76 realMainForm.Show(); 77 } 78 else 79 { 80 base.OnMainFormClosed(sender, e); 81 } 82 } 83 else 84 { 85 base.OnMainFormClosed(sender, e); 86 } 87 } 88 } 89 }
SplashForm.cs:
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 using System.Threading; 10 11 namespace WindowsTest 12 { 13 public partial class SplashForm : Form 14 { 15 private bool exit; 16 17 public bool Exit 18 { 19 get { return exit; } 20 } 21 22 public SplashForm() 23 { 24 InitializeComponent(); 25 } 26 27 //显示文字信息 28 public void PrintMsg(Object msg) 29 { 30 label1.Text = msg.ToString(); 31 } 32 33 //关闭启动窗体,如果需要中止程序,传参数false 34 public void CloseForm(Object o) 35 { 36 this.exit = Convert.ToBoolean(o); 37 this.Close(); 38 } 39 40 private void SplashForm_Load(object sender, EventArgs e) 41 { 42 ThreadPool.QueueUserWorkItem(new WaitCallback(Program.InitApp), this); 43 } 44 } 45 }
只需要将Program.cs里的InitApp里的Thread.Sleep改成实际的load resource代码即可
标签:
原文地址:http://www.cnblogs.com/yingzhongwen/p/4870132.html