| 我正在學習 Microsoft .NET 架構,不太理解控制項和組件之間的差別。我知道這些術語可以互用,但什麼時候從 Control 派生,什麼時候從 Component 派生呢?Linda Berno 好問題!簡單說來,控制項就是具有使用者介面的組件。要說的具體一點,就得回顧早期 Windows 的曆史根源,當時控制項指任何子視窗——按鈕、列表框、編輯框或者某個對話方塊中的靜態文本。從概念上講,這些視窗——控制項——類似用來操作收音機或小電器的旋鈕和按鈕。隨著控制項數量的增加(組合框、日期時間控制項等等),控制項逐漸成為子視窗的代名詞,無論是用在對話方塊中還是用在其它種類的主視窗中。沒過多久 BASIC 程式員開始編寫他們自己專用的控制項,自然而然地人們便想到共用這些控制項。共用代碼的方法之一是通過磁碟拷貝,但那樣顯然效率低下。必須要有一種機制使開發人員建立的控制項能夠在其它程式員的應用中輕而易舉地插入,這便是VBA控制項,OLE控制項,OCX和最後ActiveX 控制項的動機。 這就是控制項和組件之間產生混淆之所在。因為為瞭解決控制項的可複用問題,所有這些技術必須首先解決更為一般的組件重用問題。(COM,如果你還記得它的話,意思是元件物件模型)。在軟體行話中,組件這個術語指任何可複用的對象或任何可與其它對象互動的代碼體。子程式的發明,曾經一度成為程式員趨之若鶩的軟體工程聖杯:一種統一的編程理論,它使程式員從基本構建塊——也就是用所選語言編寫的各種組件建立大型系統。從子程式演變到OOP,到DLLs,再到COM,再到.NET架構的每一種新的編程範例都代表了一種不同的提供可重用性的方案。VBX使用DLLs的固化名稱。COM使用介面和IUnknown。.NET架構使用微軟的中繼語言(MSIL)層和通用語言執行平台(CLR)來提供統一的粘合。 因此,控制項是組件的一個主要樣本(並且曆史上曾驅動著組件的開發),控制項又不僅僅是唯一的一種組件。組件不需要顯示任何資訊或使用者介面。組件可能實現科學計算,收集效能資料,計算1971年1月1日到現在的毫秒數,仰或是讀取布希總統競選活動保險箱裡的美金數。Figure 4 顯示了 Visual Studio .NET 中的非控制群組件例子。 Figure 4 組件
在 .NET 架構中,術語控制項和組件為 .NET 賦予了專門的意義。Component 類為被用於設計層面的對象如 Windows Forms Designer (Windows 表單設計器)或 Web Forms Designer (Web Form設計器)提供了基本實現。某個 Component 是任何可以被拽到某個表單的任何東西。Component 類實現IComponent,ISite 和 IContainer。這些介面比起其來自 OLE 時期的 COM 堂兄弟要簡單得多。 IContainer 比起帶有 Add/Remove 方法的組件列表以及組件屬性來要稍微複雜一點,它獲得的組件是一個 ComponentCollection (組件集合)。 IComponent 從 IDisposable 派生而來,並且只有一個屬性,Site,擷取組件的ISite介面。Component 可能有,也可能沒有Site。ISite 有四個屬性,其中包括Name和DesignMode,它控制該組件是否處於——還能是什嗎?——設計模式。ISite 派生於另一個介面,IServiceProvider,它只有一個方法,GetService。在COM中,IServiceProvider 類似 QueryInterface——用它可以通過ID來查詢某個對象的介面,但是與 QueryInterface 不同的是該對象本身不用去實現這個介面,它僅僅知道在哪裡和如何擷取它即可。同樣,在.NET架構中,IServiceProvider 是一種擷取其它介面或對象的通用方法——服務——對象不用實現它就知道的一種服務。 .NET架構使得編寫可複用組件輕鬆自如,不再需要 IDL,不再需要類型定義語言,不再需要費力的設計時支援。通過反射(reflection)的魔法,CLR 從代碼本身就已經知道了該知道的一切,所有的類都在掌控之中。為了添加設計時支援,你只要用額外的設計器標記你的屬性即可。例如,在託管C++中: // in CMyControl [Category(S"Appearance")] [Description(S"Specifies widget foreground color.")] _property Color get_ForeColor() { ... } _property void set_ForeColor(Color value) { ... }現在表單設計器在“外觀”(Appearance)中列出你的 ForeColor 屬性並使用協助描述(Description)。有關設計時屬性的更多內容,請參考.NET架構文檔中的“組件的設計時屬性” Figure 5 類階層
Figure 5 顯示了.NET架構中的類階層,它能說明上述討論的問題。正如你所看到的,Control 從 Component 派生而來。這是用另外一種方式來說明控制項即組件(反之則不然)。更具體地講,控制項是一個用使用者介面的組件——能繪製東西並能與使用者互動。Control 類還是所有託管視窗類別的基類——表單、按鈕、柵格、面板、工具列等等。Control 類是定義 WndProc 和 ClientSize 以及所有標準視窗事件如 GotFocus 和 Click 的地方。Web控制項(System.Web.UI.Control)也是組件,不過從嚴格的意義上講,它不是從 System.ComponentModel.Component 派生的。(對於 Web 控制項,其名字空間為 System.Web.UI,Control 本身實現 IComponent。) 除了實現 IComponent 之外,System.ComponentModel.Component 還提供了所有組件需要的列集支援,但它是通過從 MarshalByRefObject 派生來實現的。如果想產生一個值列集組件,可以從 MarshalByValueComponent 派生(它實現了 IComponent,IDisposable 和 IServiceProvider)。System.Data.DataColumn,DataSet 和 DataTable 都是是值列集組件的例子。這些對象跨機器/進程邊界傳遞其實際資料。 如果你正在編寫其他人也能用表單設計器拖拽到其表單的可重用的小工具,那麼你必須從 Component 派生。如果你的小工具還具備使用者介面——能建立視窗,繪畫或與使用者互動——那麼就應該從 Control 派生。明白了嗎? 向 Paul 提問和評論請發到 cppqa@microsoft.com. |