窗體嵌套
經驗豐富的Visual Basic開發者知道多文檔界面(MDI)應用程序能夠包含子窗體,那些子窗體由MDI父窗體管理。但是如果沒有MDI的能力你怎樣實現包含嵌套窗體?例如一個MDI子窗體也可能需要包含另一個窗體。
有時能夠使用用戶控件(UserControl)實現這種功能,但是如果你真的需要把一個窗體嵌套進另一個窗體,有多種方法可以實現。窗體衍生自Control類,這意味著它能被放入另一個窗體的控件集合中,使用如下的邏輯:
|
但是很不幸,這段代碼將會導致一個運行時(runtime)異常(見圖1)。

圖1.試圖把一個窗體添加到另一個窗體的控件集合時出現的運行時錯誤
為了避免這種異常,該窗體的TopLevel屬性必須設置為False(見下面的代碼)。
|
圖2顯示的是使用上面的邏輯實現的一個窗體嵌入另一個窗體。嵌入的窗體有一個標題條(它的顏色是未激活的系統顏色),因此該嵌入窗體能在容器窗體內四處拖動。在圖2中,該窗體從它的開始位置(左上角)拖到了右下角。

圖2.在容器窗體中有一個嵌入的窗體。嵌入的窗體能在容器窗體中拖動。
通常在顯示嵌入的窗體前先設置它的位置。這只需要簡單的設置嵌入窗體的Left和Top屬性。嵌入窗體的位置與容器窗體是相對的。
與MDI子窗體不同,嵌入窗體能覆蓋容器窗體上的控件。圖3顯示了它們的不同。

圖3.嵌入窗體(左)可以覆蓋容器窗體上的控件。MDI子窗體(右)不能覆蓋MDI父窗體上的控件。
在右邊的MDI例子中,沒有辦法使按鈕隱藏在子窗體的后面。但是在左邊該按鈕被嵌入窗體覆蓋了。
當窗體第一次被嵌入時,它將顯示在容器窗體上的已存在的控件的后面。當它被點擊時,它走向前臺并停留在那兒。這會打擾用戶,但是能通過插入下面的代碼防止這種情況發生:
|
嵌入的窗體可以包含其它的嵌入窗體,沒有實際的限制。圖4顯示了一個本身包含嵌入的窗體的嵌入窗體。

圖4.一個包含嵌入窗體的嵌入窗體
處理數據行(DataRow)
Windows窗體中的數據綁定列表框和組合框很節省時間。典型的代碼如下(假定已經建立了SqlDataAdapter或者其它部件獲取數據):
|
在這種情況下,代碼使用Northwind數據庫的顧客記錄工作。DisplayMember屬性設置為你希望用戶在列表框中看到的記錄字段,它是customers表的CompanyName。通常ValueMember屬性設置為數據表中的一個鍵字段,對于customer來說是CustomerID。一旦用戶選擇了列表框中的一行,很容易使用列表框的SelectedValue屬性獲得鍵字段:
|
但是有可能需要一個與被選擇項相關的整個數據行對象的引用。例如,如果被選擇的行需要被刪除,就不知道鍵了。你需要一個數據行的引用以使用Delete方法。
典型的Visual Basic開發者通常這樣想:"我已經得到了該行的鍵了,我將編寫一些邏輯來查找使用該鍵的行"。這樣可以實現,但是有更好的實現方法?梢允褂靡恍写a獲取與列表框中選項關聯的數據行:
|
通常該邏輯不會憑直覺出現,即使對經驗豐富的開發者。為了解釋這是怎樣實現的,我把上面的一行拆成幾行,下面的代碼與上面代碼的功能相同:
|
DataRowView類是數據行的包裝,它被多個Windows窗體控件使用。它使得顯示與控件中的數據行相關的數據更加容易。當列表框被數據綁定到數據表時(假定列表框中的有些行當前被選定了),列表框的SelectedItem屬性保存了一個DataRowView對象。
這意味著我們能把列表框的SelectedItem屬性轉換到DataRowView對象,這就是上面代碼中的第二行實現的。接著DataRowView暴露一個Row屬性,它指向被包裝的數據行。上面的代碼聲明了一個數據行并設置了Row屬性。
轉換對象的類型以訪問它的接口的技術在Visual Basic 6.0中不是經常使用,但是在Visual Basic .NET中這是經常的。有了上面的例子后,大多數有經驗的開發者迅速跟上了這種技術。
數據行的引用(dr)可用于用任何方式維護行。訪問數據行中的任何特定字段是可行的。行中的數據可以被改變,能使數據行的Delete方法把該行標識為刪除,或者從數據表的行集合中刪除該行。下面的代碼標識刪除了一行:
|
使用主鍵(由ListBox.SelectedValue返回)查找下層數據行的方法需要很多代碼,要花很長時間,執行起來更慢。對于剛開始使用Visual Basic .NET的程序員來說花幾個小時編碼是很正常的。理解上面的技術節約了很多時間,更簡單、容易維護代碼。
給控件綁定顏色
數據綁定能應用于控件的任何屬性。我看到過很多人提到能夠綁定文本框的背景顏色到數據項,舉個例子,超期的帳號的背景色顯示紅色。
但是如果你試圖使用數據集或者數據表實現該功能,將會遇到問題。數據行只能保持受到限制的數據類型,并且不支持Color類型。如果你不能把顏色存儲在數據中怎么能綁定顏色呢?
有些途徑可以解決這個問題,但是最簡單的是用綁定到自定義數據對象代替綁定到數據表。自定義業務對象的屬性可能是Color型的,這樣的屬性能綁定到控件的BackColor屬性。
為了演示,我定義了下面的自定義事務對象:
|
注意只讀的BackColor屬性從Balance屬性中得到值,并且為負平衡(negative balance)暴露了一個不同的顏色。該類的其它元素很直接。
現在我們建立一個界面來操作這些對象的集合(見圖5)。

圖5.演示背景顏色綁定的窗體(設計時)
上面的三個文本框都用于保持當前Account對象的數據。它們分別叫txtAccountID、txtCustomerName和txtBalance。顯示Load的按鈕叫btnLoad,用于載入帳號集合。另兩個按鈕在記錄間導航,分別叫btnBack 和 btnForward。
帳號對象集合可以保持在ArrayList(數組列表)中,因此下面一行代碼應該在窗體代碼的最前面:
|
下面是Load方法的Click事件代碼。它建立了一些Account對象并把它們放入一個集合中,接著把該集合綁定到文本框。
|
注意最后兩行。txtBalance的Text屬性綁定到一個帳號的Balance屬性,并且該控件的BackColor屬性綁定到帳號對象的BackColor屬性。它演示了.NET框架組件綁定一個以上屬性到不同數據項。
現在點擊btnBack的Click事件,填入一下代碼:
|
啟動項目并點擊Load按鈕。ABC公司的記錄出現在文本框中。點擊向前按鈕,就是XYZ公司記錄,同時,txtBalance的背景色變為橙紅色(見圖6)。

圖6.數據綁定窗體顯示了一個負平衡記錄,引起Balance字段的背景色不同
過了該帳號記錄后,該文本框的背景顏色將變回正常色。
Account類不是特別復雜。但是這個例子最少讓你看到了怎樣綁定不同屬性(例如控件顏色)。
修改數據窗體向導
使用數據窗體向導(Data Form Wizard)你能迅速獲得文件操作程序窗體。為了使用它,選擇Project菜單的Add New Item,接著選擇Data Form(數據窗體)。該向導將一步一步幫助你指定希望的數據,并為那些數據建立一個文件操作程序。圖7顯示了一個從Northwind數據庫的Products表中產生的數據窗體。

圖7. Northwind Products表的文件維護窗體,它由數據窗體向導產生
但是這種自動生成程序有一個重要的限制。如果被訪問的數據有任何字段不能為空(因為數據庫大綱不允許空值),那么向導生成的程序不能添加記錄。當點擊Add按鈕時,將出現錯誤信息,提示記錄中的第一個字段不允許為空(如果你沒有最新的服務包,你也許看不到該錯誤信息,但是程序拒絕添加記錄)。
該問題是由于數據窗體向導使用BindingContext對象給綁定的數據表添加了一行。下面是btnAdd_Click事件程序失敗的代碼:
|
解決方法是為新行略過BindingContext對象。下面是添加新行的典型代碼,該代碼應該代替上面的一行代碼:
|
在用數據表的NewRow方法獲得一個空行時,該代碼給不能為空的字段填充值。接著數據表接受新行,通過數據表行集合的Add方法添加新行。
有了這個補丁后,該數據程序能夠運行?梢詫λM行增強或改變,例如改變SupplierID 和CategoryID字段以從包含供應商和類別的下拉列表中選擇。
在.NET框架組件中顯示時間
開發過程過程中我們通常對特定代碼片運行所花的時間很感興趣。當然有一些標準程序和代碼工具可以查看到它,但是有經驗的Visual Basic 6.0開發者有更快的辦法。僅僅捕捉開始時間(使用Now關鍵字)和終止時間(再次使用Now關鍵字),兩種相減,就能知道結果了。
如果使用Visual Basic .NET編寫,首先嘗試的代碼可能是這樣的:
|
但是這段代碼的最后一行有語法錯誤。錯誤消息是"日期類型沒有定義'-'操作符"。這意味著我們不能執行減法。日期數據類型不支持減法操作,那么我們怎么得到兩次時間的差別呢?
答案就是使用TimeSpan類。它是用于保持時間段的。上面的代碼看起來與.NET框架組件中的相似:
|
計算使用的是類Date的Subtract方法。最后一行將輸出時間的跨度,格式化成小時、分鐘和秒(包括秒的小數位)。典型的輸出是這樣的:
|
該時間跨度是10秒半。盡管顯示了7位小數,但是只能相信兩位,但是已經足夠了。
結論
.NET是一種有趣的技術。.NET框架組件有超過8000個類!在如此龐大的內容中卻很容易找到有用的功能。我希望上面的幾個技巧在你的應用程序中能夠用到。
延伸閱讀
文章來源于領測軟件測試網 http://www.kjueaiud.com/