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

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
