概述
何謂模式窗體?簡單的可以理解為窗體對話框,用戶必須在完成該窗體上的操作或關閉窗體後才能返回打開此窗體的窗體。本文不對模式窗體的定義、特征、功能做具體討論,主要把重點放在如何在.net窗體應用程序中有效的使用模式窗體,解決使用模式窗體中碰到的常見問題。
模式窗體的屬性設置
在.net中一個System.Windows.Forms.Form類就表示一個窗體,通過visual studio 2005設計器能夠直接添加窗體,切換到設計模式,在屬性窗口中會顯示屬於該窗體的屬性和事件。參照標准的模式窗體,以visual studio 2005程序的菜單工具->選項打開的那個選項對話框為例,對於設計器初始化的窗體還是需要進行一番設置才能達到專業化。令人高興的是這些設置都可以在設計器模式中通過屬性設置實現,筆者將通過代碼來實現相應功能,下面對其進行詳細描述。
Form.StartPosition屬性,確定窗體第一次出現時的位置。這裡設置為在父窗體的中間顯示。this.StartPosition = FormStartPosition.CenterParent;
Form.HelpButton屬性,確定窗體的標題欄上是否有“幫助”按鈕。設置顯示,看上去更人性化,但實際不一定會對幫助功能進行實現。
this.HelpButton = true;
Form.MaximizeBox屬性,確定窗體標題欄的右上角是否有最大化框。設置不讓她顯示。
this.MaximizeBox = false;
Form.MinimizeBox屬性,確定窗體標題欄的右上角是否有最小化框。設置不讓他顯示。
this.MinimizeBox = false;
Form.ShowIcon屬性,指示是否在窗體的標題欄中顯示圖標。設置不顯示。
this.ShowIcon = false;
Form.ShowInTaskbar屬性,確定窗體是否出現在Windows任務欄中。這個當然要節省任務欄的寶貴空間。
this.ShowInTaskbar = false;
Form.FormBorderStyle屬性,指示窗體的邊框和標題欄的外觀和行為。設置這個屬性將不允許拖動調整窗體的大小,同時Icon屬性將失效,並不顯示窗體標題欄圖片。
this.FormBorderStyle = FormBorderStyle.FixedDialog;
Form.ControlBox屬性,確定窗體是否有“控件/系統”菜單框。通過該設置可以隱藏標題欄的控制按鈕。在有些時候還是有必要設置為False,標題欄就不會再有控制按鈕。
this.ControlBox = false;
通過對以上屬性的設置,基本實現模式窗體的靜態功能。對於是否允許調整窗體的大小可根據實際情況而定。
模式窗體中的按鈕
模式窗體中(比如visual studio 2005中的“選項”對話框)一般會有兩個基本按鈕,一個[確定]按鈕用來提交,另一個[取消]按鈕用來撤銷提交,有時候會增加一個[應用]按鈕,不過像“幫助”菜單中的“關於”模式窗體可能就只有一個[確定]按鈕。Windows窗體為用戶操作友好性提供了比較好的支持。我們可以在Form設計界面的屬性設置中找到AcceptButton和CancelButton兩個屬性,默認值為空即顯示(無)。在屬性中可以通過選擇窗體上的按鈕來設置值。屬性修改生成的代碼如下。
先定義兩個Button,
private System.Windows.Forms.Button buttonOK;
private System.Windows.Forms.Button buttonCancel;
窗體的“接受”按鈕。如果設置了此按鈕,則用戶每次按“Enter”鍵都相當於“單擊”了該按鈕。
this.AcceptButton=this.buttonOK;
窗體的“取消”按鈕。如果設置了此按鈕,則用戶每次按“Esc”鍵都相當於“單擊”了該按鈕。
this.CancelButton = this.buttonCancel;
可見可以通過快捷鍵來方便的訪問特定按鈕,但這個有一些例外,比如窗體焦點剛好在buttonCancel上,當按{Enter}時實際按下的鍵會是buttonCancel而不是buttonOK,如果焦點停在第三個按鈕上,那{Enter}按下相當於點擊了該按鈕。另一個細節是通過鼠標點擊按鈕和快捷鍵操作按鈕的表現行為不一樣,快捷鍵操作Button不會顯示按鈕被按下的顯示效果,看上去什麼都沒有發生。
模式窗體的打開與關閉
談到模式窗體的打開,一般通過Form.ShowDialog ()方法或她的一個重載Form.ShowDialog (IWin32Window)來實現,其中後一個方法將窗體顯示為具有指定所有者的模式對話框。如下代碼所示,
OptionForm form = new OptionForm();
//form.ShowDialog();
form.ShowDialog(this);
對於指定所有者方式打開的模式窗體可以在模式窗體內部獲取主窗體的引用,
//在模式窗體內部訪問所屬窗體
MainForm form=this.Owner as MainForm;
注意,如果以Form.ShowDialog ()方式打開,那Form.Owner屬性會是空引用。
談到模式窗體的關閉,先來看一下模式窗體關閉後的返回值。無論是調用Form.ShowDialog ()方法還是Form.ShowDialog (IWin32Window)方法,都會在模式窗體關閉時返回System.Windows.Forms.DialogResult枚舉值。參考 MSDN,該枚舉包含的值如下,
DialogResult.Abort,對話框的返回值是 Abort(通常從標簽為“中止”的按鈕發送)。
DialogResult.Cancel,對話框的返回值是 Cancel(通常從標簽為“取消”的按鈕發送)。
DialogResult.Ignore,對話框的返回值是 Ignore(通常從標簽為“忽略”的按鈕發送)。
DialogResult.No,對話框的返回值是 No(通常從標簽為“否”的按鈕發送)。
DialogResult.None,從對話框返回了 Nothing。這表明有模式對話框繼續運行。
DialogResult.OK,對話框的返回值是 OK(通常從標簽為“確定”的按鈕發送)。
DialogResult.Retry,對話框的返回值是 Retry(通常從標簽為“重試”的按鈕發送)。
DialogResult.Yes,對話框的返回值是 Yes(通常從標簽為“是”的按鈕發送)。
由於某些原因在實際用戶操作中比如選項數據無法保存,輸入的設置數據有問題,點擊[確定]按鈕需要阻止窗體的關閉以
對輸入的設置進行調整。對於一些開發者在技術社區貼的阻止模式窗體關閉的代碼,我認為不是很好的實現。以下用代碼來描述該實現,注意其中用到了三個事件。
//注冊窗體關閉事件
this.FormClosing += new
System.Windows.Forms.FormClosingEventHandler(this.OptionForm_FormClosing);
//注冊確定按鈕事件
this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click);
//注冊取消按鈕事件
this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click);
三個事件對應的事件處理程序如下,
//確定按鈕處理程序
private void buttonOK_Click(object sender, EventArgs e)
{
//假設textBoxPath用來記錄目錄路徑,如果不存在要求用戶重新設置。
if (this.textBoxPath.Text.Trim().Length == 0)
{
MessageBox.Show(輸入路徑信息不對!);
this.textBoxPath.Focus();
}
else
{
this.DialogResult = DialogResult.OK;
}
}
//取消按鈕處理程序
private void buttonCancel_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Cancel;
}
//窗體關閉處理程序,在關閉窗體時發生。
private void OptionForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (this.DialogResult != DialogResult.Cancel && this.DialogResult !=
DialogResult.OK)
e.Cancel = true;
}
上面的代碼都正常,就是事件寫多了,對上面代碼進行修改,去掉[取消]按鈕事件和窗體關閉事件以及相關的事件處理程序。首先需要在窗體構造函數中通過設置按鈕的DialogResult屬性來實現返回特定的DialogResult。
this.buttonOK.DialogResult=System.Windows.Forms.DialogResult.OK;
this.buttonCancel.DialogResult=System.Windows.Forms.DialogResult.Cancel;
注冊確定按鈕事件,
//注冊確定按鈕事件
this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click);
//確定按鈕處理程序
private void buttonOK_Click(object sender, EventArgs e)
{
if (this.textBoxPath.Text.Trim().Length == 0)
{
MessageBox.Show(輸入的路徑信息不對!);
this.textBoxPath.Focus();
//設置文本框焦點
this.DialogResult = DialogResult.None;
}
}
可見,新的實現方式代碼減少了一半。
.Net Framework提供的模式窗體
.net Framework為我們提供了一些比較常用的對話框,在開發過程中省了不少事,以下對其進行介紹。
MessageBox。顯示可包含文本、按鈕和符號(通知並指示用戶)的消息框。通過MessageBox.Show 靜態方法來打開模式對話框。
public static DialogResult Show ( string text );
該方法包含多個重載版本。復雜的一個方法如下,
public static DialogResult Show ( IWin32Window owner, string text,
string caption, MessageBoxButtons buttons, MessageBoxIcon icon,
MessageBoxDefaultButton defaultButton, MessageBoxOptions options,
string helpFilePath, HelpNavigator navigator, Object param ) ;
根據不同的參數可以定制對話框的行為。
另外一些對話框提供了特定功能。
OpenFileDialog。打開文件對話框,從FileDialog類繼承,提示用戶打開文件,無法繼承此類。對於文件的打開操作屬於比較常見的。
SaveFileDialog。保存文件對話框,從FileDialog類繼承,提示用戶選擇文件的保存位置。無法繼承此類。
FolderBrowserDialog。目錄浏覽對話框,從CommonDialog類繼承,提示用戶選擇文件夾。無法繼承此類。 FontDialog。字體設置對話框,從CommonDialog類繼承,提示用戶從本地計算機上安裝的字體中選擇一種字體。可繼承該類。
ColorDialog。顏色設置對話框,從CommonDialog類繼承,表示一個通用對話框,該對話框顯示可用的顏色以及允許用戶定義自定義顏色的控件。可繼承該類。
PageSetupDialog。打印頁面設置對話框,從CommonDialog類繼承,允許用戶更改與頁面相關的打印設置,包括邊距和紙張方向。無法繼承此類。
PrintDialog。打印對話框,從CommonDialog類繼承,允許用戶選擇一台打印機並選擇文檔中要打印的部分。無法繼承此類。
PrintPreviewDialog。打印預覽對話框,從Form類繼承,表示包含 PrintPreviewControl 的對話框窗體。可繼承該類。由於該類從Form類繼承,所以除了通過
PrintPreviewDialog.ShowDialog ();
PrintPreviewDialog.ShowDialog (IWin32Window);
方法以模式方式打開窗體外,還可以通過PrintPreviewDialog.Show ();
或其重載PrintPreviewDialog.Show (IWin32Window);方法按正常非模式方式打開。
上面列舉的文件對話框抽象基類FileDialog是從CommonDialog抽象類繼承,因此所有從該類繼承的對話框都可以通過CommonDialog.ShowDialog ();或其重載CommonDialog.ShowDialog (IWin32Window);方法以模式方式打開窗體。