設(shè)計(jì)啟動(dòng)屏幕
*********************************************************
版權(quán)聲明:
此文章是本人正在撰寫(xiě)之 .NET 4.0 著作中的一部分,出于技術(shù)共享與交流目的而發(fā)布,作者金旭亮擁有全部版權(quán)。任何人及機(jī)構(gòu)不得將其用于商業(yè)用途,如收費(fèi)培訓(xùn)及出版同類(lèi)技術(shù)書(shū)籍,有這方面需求的個(gè)人及培訓(xùn)機(jī)構(gòu)請(qǐng)與本人直接聯(lián)系。
本人聯(lián)系方式:
JinXuLiang@bit.edu.cn 北京理工大學(xué)計(jì)算機(jī)學(xué)院 100081
更多技術(shù)與學(xué)習(xí)資源請(qǐng)關(guān)注作者博客:
http://blog.csdn.net/bitfan
金旭亮
2009.8.26
*************************************************************************
許多大家熟知的應(yīng)用程序都有 啟動(dòng)屏幕 (另一常見(jiàn)稱(chēng)呼為“ 啟動(dòng)窗體 ”),比如 Word 在啟動(dòng)時(shí)就會(huì)先呈現(xiàn)一張圖片,然后再顯示主窗體。
另外一些應(yīng)用程序具有更復(fù)雜的功能的啟動(dòng)窗體,比如著名的 PhotoShop 軟件在啟動(dòng)屏幕上會(huì)動(dòng)態(tài)掃描并裝載用戶(hù)安裝的各種插件,并在啟動(dòng)窗體上顯示出相關(guān)信息。
在這一小節(jié)中,我們將介紹兩種類(lèi)型的啟動(dòng)屏幕:一種似于 Word ,僅快速顯示一張圖片以通知用戶(hù)“程序已經(jīng)運(yùn)行,請(qǐng)稍候……”,另一種則類(lèi)似于 PhotoShop ,在顯示啟動(dòng)屏幕的同時(shí),程序會(huì)在后臺(tái)進(jìn)行系統(tǒng)初始化。
第一種方式的啟動(dòng)屏幕非常易于實(shí)現(xiàn),甚至簡(jiǎn)單到不用寫(xiě)一行代碼。
第二種方式則比較復(fù)雜一些,詳細(xì)分析一下:
這種類(lèi)型的應(yīng)用程序在程序初起時(shí)都有兩個(gè)線程,一個(gè)是主線程,通常負(fù)責(zé)在完成所有的系統(tǒng)初始化工作后顯示主窗體,而啟動(dòng)屏幕則由另一線程負(fù)責(zé)創(chuàng)建并顯示,通常要求將主線程所執(zhí)行系統(tǒng)初始化的信息顯示在啟動(dòng)屏幕上,很明顯,這是一個(gè)兩個(gè)線程同步及跨線程訪問(wèn)可視化控件的問(wèn)題。如果讀者閱讀了本書(shū)前面的章節(jié),則在這兒解決這個(gè)問(wèn)題已沒(méi)有任何難度,但仍然需要有一些技巧。
1 在程序啟動(dòng)時(shí)顯示一張圖片
這是最容易實(shí)現(xiàn)的一種啟動(dòng)屏幕。只要安裝了 .NET Framework 3.5 SP1 以上的版本,可以不需要寫(xiě)一句代碼。其步驟如下:
1 在 Visual Studio 2008 SP1 或 Visual Studio 2010 中將啟動(dòng)屏幕圖片加入到項(xiàng)目中。
2 設(shè)定此圖片的“ Build Action ”屬性為“ SplashScreen ”( 圖 1 ):
圖1 為啟動(dòng)屏幕圖片文件設(shè)置“ Build Action ”
編譯并運(yùn)行程序,可以看到你所選擇的圖片在屏幕上顯示約 0.5 秒后自動(dòng)消失,程序主窗體出現(xiàn)。
2 多功能程序啟動(dòng)屏幕的實(shí)現(xiàn)
請(qǐng)看示例程序 SplashScreenForWPF ,程序運(yùn)行時(shí)如圖 2 所示:
圖2 啟動(dòng)屏幕
此示例程序在運(yùn)行時(shí)啟動(dòng)了兩個(gè)線程:主線程和 UI 線程,這兩個(gè)線程所完成的工作如圖 3 所示:
圖3 兩個(gè)線程的任務(wù)流程圖
圖 3 中,雙向箭頭表示這兩個(gè)線程的這兩個(gè)處理工作之間存在著線程同步關(guān)系。下面簡(jiǎn)要敘述一下示例程序中的技術(shù)關(guān)鍵點(diǎn)。
使用 Visual studio 創(chuàng)建 WPF 應(yīng)用程序時(shí),默認(rèn)情況下會(huì)生成一個(gè) App.xaml 和 App.xaml.cs 作為程序的入口點(diǎn),但如果要顯示啟動(dòng)屏幕,就不能使用它來(lái)啟動(dòng)程序了。
首先刪除這兩個(gè)文件,然后,向項(xiàng)目中添加一個(gè) Program.cs 類(lèi)文件,此文件與 Visual studio 為控制臺(tái)應(yīng)用程序生成的結(jié)構(gòu)一樣,也是在 Program 類(lèi)中放置一個(gè) Main() 函數(shù)作為程序入口點(diǎn)。
雙擊“解決方案資源管理器”中項(xiàng)目節(jié)點(diǎn)下的“ Properties ”節(jié)點(diǎn),在打開(kāi)的項(xiàng)目屬性卡片中設(shè)置程序的啟動(dòng)對(duì)象為 Program 類(lèi),這將確保程序從 Main() 函數(shù)開(kāi)始執(zhí)行。
下面向項(xiàng)目中添加一個(gè)將作為啟動(dòng)屏幕的窗體,可以根據(jù)你的美術(shù)天份自行設(shè)計(jì),在本示例中,我就放了一個(gè)背景圖片,一個(gè) TextBlock 用于顯示文字信息,一個(gè) ProgressBar 用于顯示工作進(jìn)度。
很重要的,由于啟動(dòng)屏幕的窗體需要被主線程訪問(wèn),因此,需要給其添加一個(gè)公有的方法用于顯示外部傳過(guò)來(lái)的信息
public void ShowProgress(int Value)
{
pgbProcess.Value = Value;
tbInfo.Text =" 已完成 "+ Value.ToString() + "%";
}
所有的關(guān)鍵工作由運(yùn)行于主線程中的 Main() 函數(shù)完成。
[STAThread]
static void Main()
{
// 在一個(gè)獨(dú)立 UI 線程中顯示啟動(dòng)屏幕
Thread th = new Thread(ShowSplashScreenThenMainWindow);
th.SetApartmentState( ApartmentState.STA );
th.Start();
// 啟動(dòng)初始化過(guò)程
SystemInit();
}
注意需要設(shè)置線程模式為 STA ,這是為了與 Windows Form 相兼容而一直沿用下來(lái)的。
上述代碼中的線程函數(shù) ShowSplashScreenThenMainWindow() 負(fù)責(zé)創(chuàng)建啟動(dòng)屏幕和顯示主窗體:
static winSplash win = null; // 引用啟動(dòng)屏幕對(duì)象
static void ShowSplashScreenThenMainWindow()
{
win = new winSplash();
win.ShowDialog();
// 顯示主窗體
Application myApp = new Application();
myApp.Run(new winMain());
}
注意上述代碼中通過(guò)調(diào)用 ShowDialog() 方法顯示啟動(dòng)屏幕并阻塞當(dāng)前 UI 線程的進(jìn)一步執(zhí)行。
主線程在啟動(dòng) UI 線程之后,調(diào)用 SystemInit() 方法開(kāi)始系統(tǒng)初始化過(guò)程,在此可以放置各種初始化代碼,然后使用 win.Dispatcher.Invoke 和 BeginInvoke 方法在啟動(dòng)屏幕上顯示信息。
這里面的關(guān)鍵之處在于, SystemInit() 方法在執(zhí)行時(shí)必須確保啟動(dòng)屏幕窗體已經(jīng)顯示并可以接收外界傳入的信息,為此,示例程序設(shè)置了一個(gè) ManualResetEvent 對(duì)象作為線程同步對(duì)象,并將其初始化為 non-singaled 狀態(tài):
public static ManualResetEvent mre = new ManualResetEvent (false);
在 SystemInit() 方法的開(kāi)頭,調(diào)用
mre.WaitOne();
阻塞等待通知。
而在啟動(dòng)屏幕的 Loaded 事件(它表示窗體已初始化完成)中觸發(fā) ManualResetEvent 對(duì)象的狀態(tài)轉(zhuǎn)換:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// 通知主線程自己已經(jīng)啟動(dòng)完畢
Program.mre.Set();
}
當(dāng)系統(tǒng)初始化完成, SystemInit() 方法再通過(guò) win.Dispatcher.BeginInvoke 方法向 UI 線程提交一個(gè)“關(guān)閉啟動(dòng)屏幕”的工作項(xiàng)請(qǐng)求,從而導(dǎo)致 UI 線程關(guān)閉啟動(dòng)屏幕,進(jìn)而創(chuàng)建應(yīng)用程序主窗體并顯示,應(yīng)用程序就可以被用戶(hù)所訪問(wèn)了。
上面就是本示例的所有技術(shù)關(guān)鍵點(diǎn),其余的技術(shù)細(xì)節(jié)請(qǐng)自行閱讀源碼。
這個(gè)示例采用 WPF 開(kāi)發(fā),但其中所介紹的技巧完全可用于 Windows Form 。筆者開(kāi)發(fā)了對(duì)應(yīng)的 Windows Form ,其示例項(xiàng)目名為 SplashScreenForWinForm ,供讀者參考。
===============================
(注:給的示例項(xiàng)目為 VS2010 格式,使用 VS2008 的讀者請(qǐng)新建一個(gè)空白的 Windows Form 或 WPF 項(xiàng)目,然后手工向其中追加文件)。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元

