一前言
Microsoft® Visual Basic® 的組件支持歷來都是它的一大賣點於是第三方軟件開發商們紛紛開發出各種具有新功能性的可視控件 (也有少數非可視控件) 供 Visual Basic 程序員選用這種特殊的 Visual Basic 開發形式創造了無數的第三方控件——有的是共享軟件/自由軟件有的則被放到櫃台上銷售現在人們甚至可以直接用 Visual Basic 開發自己的可視/非可視組件了於是組件的數量迅速增長其中相當一部分都是程序員 (或者開發小組) 為針對自己的開發任務設計的
注意你或你的開發小組過去購買的 Microsoft ActiveX 控件往往無須修改或重寫就能直接移植到微軟 NET 環境下具體而言只要進入 Microsoft Visual Studio® NET 的 IDE (集成開發環境) 環境依次從菜單中選擇工具 Tool > 自定義工具箱 Customize Toolbox) 或者使用 NET 框架實用程序 Aximpexe (ActiveX 控件導入程序) 就能讓 NET 應用程序中調用現成的 ActiveX 控件了可是一旦某個控件在 NET 環境下工作不正常它的作者恐怕就應該考慮升級該控件了所以為了能在 NET 環境中正常使用購來的第三方 ActiveX 控件就應該到開發商的 Web 網站去看看它有沒有出升級版或者 NET 版
在 NET 編程世界裡人們對自定義 UI 組件的需求依然存在只不過它們的創建過程有所不同本文將探討兩個問題為什麼要創建自己的 Microsoft Windows® 控件?在 Visual Basic NET 中開發控件時有哪些方面不同於以往的 / 版?
二為什麼要開發你自己的控件?
為了限制 Windows 窗體TextBox 控件的文本類型可以在窗體代碼中添加該控件的KeyPress 事件處理程序以攔截用戶的每次擊鍵並檢查該鍵對應的字符能否進入 TextBox
Private Sub TextBox_KeyPress(ByVal sender As Object _
ByVal e As SystemWindowsFormsKeyPressEventArgs) _
Handles TextBoxKeyPress
If Not CharIsDigit(eKeyChar) Then
eHandled = True
Else
eHandled = False
End If
End Sub
注意單純依靠捕捉擊鍵事件是無法確保輸入 TextBox 的文本全是數字的因為用戶有時不是直接向 TextBox 中敲入字符而是通過剪貼板粘貼字符給 TextBox 何況 TextBox 文本的初值就有可能包含非法的字符某些其它事件比如 TextChanged 等或許能夠捕捉到更多非法輸入但我更喜歡用 Validating 或者 Leave 事件它們是在用戶離開輸入控件之後才對 TextBox 進行字符合法性檢查這麼做誠然放棄了對用戶輸入的即時反應卻允許用戶首先通過剪貼板輸入輕度犯規的文本字符串 比如在禁止空格的輸入框中粘貼 然後手工糾正輸入框裡的犯規字符
向控件中手工添加事件處理程序代碼並不太難可是當你面臨更復雜的編程任務比如檢驗郵寄地址或者汽車的 VIN # (車輛識別號碼) 的字符合法性時你還會感到如此輕松嗎?此時你會希望把同一段事件處理程序用於多個窗體甚至多個項目或者將它提供給開發小組的其他成員共享然而提取窗體中的代碼片段連同安裝指南和控件的命名規則一起發布卻是一個惡夢的開端好在天無絕人之路你只要把它連同一個自定義控件發布就不會遭遇這種惡夢了因為此時用戶界面和相關代碼都位於獨立的組件中而組件的發布相對要容易得多通過組件發布的代碼片段在升級上也方便些你只需發布新版的組件即可再也不必通過種種渠道公布新的代碼片段讓程序員手工覆蓋原先的代碼了!
三繼承性如何改變了控件的開發?
在 NET 中的控件開發已經和 Visual Basic 大相徑庭其根本原因就是 NET 引入了繼承性在 Visual Basic 中你只能不用控件或者直接引用現成的控件來實現各種功能性例如為了創建前面提到的自定義文本輸入框你就要新建一個 ActiveX 控件然後向其中增加一個 TextBox
注意人們通常把這種編程思路稱為容器 (containment) 或者委托(delegation)在 Visual Basic 中用於模擬繼承機制的非控件類也可以采用這種思路
此時新建的 ActiveX 控件並不會如你所願自動獲得 TextBox 的某些屬性 (比如 Text 屬性)這些屬性只能由你編碼實現更糟的是你必須用許多代碼來確保 TextBox 始終占據整個窗體你還得為新控件設計 resizing 事件處理程序當然經過一番折騰你總會完成該控件的設計任務的何況還有 ActiveX 控件界面向導能減輕你的負擔可是在 NET 環境下整個任務的完成思路都會變得完全不同
繼承性能避免控件開發中的某些重復代碼因為它能讓 NET 控件直接獲得任何其它控件的功能性例如為了創建自己的 TextBox 控件你可以繼承現有的 TextBox 控件而不是 UserControl 控件新控件繼承了基類控件的全部功能性因此你只需要對基類控件中沒有的功能性編碼即可下面舉一個實際的例子以下代碼能夠創建一個自定義 TextBox 控件它只允許用戶輸入數字字符
注意為了運行這段代碼你只需在Windows 應用程序模板下新建一個 Visual Basic NET 項目然後就能在 IDE 自動生成的空白窗體中試驗新控件了在項目中新建一個類 NumericTextBox 用下面的代碼替換 NumericTextBox 類文件的內容編譯該項目最後在菜單中選擇工具>自定義工具箱選中先前編譯項目得到的 exe 文件就能把新控件添加到工具箱了
Public Class NumericTextBox
Inherits SystemWindowsFormsTextBox
Protected Overrides Sub OnKeyPress(ByVal e As _
SystemWindowsFormsKeyPressEventArgs)
If Not CharIsDigit(eKeyChar) Then
eHandled = True
Else
eHandled = False
End If
End Sub
End Class
對本例來說以上代碼已經足夠了如果你還覺得它不夠完善的話請改用下列代碼它運用一種奇妙的布爾邏輯減少了代碼行數
Public Class NumericTextBox
Inherits SystemWindowsFormsTextBox
Protected Overrides Sub OnKeyPress(ByVal e As _
SystemWindowsFormsKeyPressEventArgs)
eHandled = Not CharIsDigit(eKeyChar)
End Sub
End Class
現在你的新控件已經正確顯示在窗體中了它象 TextBox 一樣處理事件並且擁有與 TextBox 一樣的方法屬性你甚至不需更多的編碼就能實現對新控件的數據綁定因為這也是基類控件 TextBox 的功能性之一
注意本控件對用戶輸入的要求十分苛刻它只允許輸入 至 的數字也就是說數字中的逗號小數點甚至負號都是非法字符
在 Visual Basic 中設計本控件時核心代碼會和本范例一樣長可是用於處理控件的 resizing 事件和實現 TextBox 組件屬性的代碼也會有這麼長由此可見NET 提供的繼承性能夠大大精簡源代碼單憑這一點NET 就已經令人歎服了何況它還有許多其它優越性更奇妙的是凡是要求使用某一控件的地方都能改用繼承該控件而來的新控件例如在任何例程中要求 TextBox 的地方都能用你的 NumericTextBox 控件不僅如此從現有控件而不是從 UserControl 類繼承而來的新控件不但具備基類控件的所有功能性還能象基類控件一樣使用繼承得到的屬性方法和事件因此任何程序員只要學過標准的 TextBox 控件就知道如何使用 NumericTextBox 控件允許繼承現有的類/控件是從Visual Basic 到 NET 的一個重大飛躍可是 NET 的優點又何止於此!在 NET 環境下Windows 窗體控件不但擁有不少強大的功能而且它們的創建也比在老版本 Visual Basic 中容易得多
四總結
無論對於個人開發小組還是軟件開發商自定義控件的開發都是功能最強大的組件技術之一眾所周知把用戶界面與功能性以軟件包的形式進行發布始終是Visual Basic 等可視化開發工具立於不敗之地的重要因素在新版的可視化工具裡仍然延續著該理念到了 NET 時代控件的開發思路已經大不相同了比如它引入了繼承等新特性好在這些新特性都是對程序員有利的因為它們有效地減少了人們的編碼負擔進而簡化了自定義控件的創建過程本文以若干控件為例向讀者介紹了自定義控件的創建過程以及控件開發中的某些重要技術當然我還希望讀者能從這些范例中學會如何創建自己的新控件
From:http://tw.wingwit.com/Article/program/net/201311/14940.html