天天看點

PropertyGrid—添加屬性Tab

PropertyGrid用來顯示和編輯對象的屬性,前面已經簡單介紹了如何使用該控件和提供不同的屬性編輯方法。前面主要講如何使用該控件,但有時,該控件無法滿足我們的需求,就需要對其進行擴充。本文主要介紹如何在PropertyGrid中添加屬性頁籤(PropertyTab)。VS自帶的屬性框有屬性和事件兩個屬性卡,下面簡單說明如何添加自己的頁籤。

  在添加頁籤之前,先來看一看PropertyGrid的組成,分析其組成對後面設計十分有用。微軟将PropertyGrid封裝的十分好了,使用起來十分的友善,但是其具體如何實作的卻不得而知。翻看MSDN,找到一點皮毛。

  首先看一下PropertyGrid類,比較複雜,發現其有一個PropertyTabs屬性,應該是PropertyGrid所包含的頁籤集合,其類型是PropertyGrid.PropertyTabCollection,很顯然它是一個PropertyTab集合類。接着看一下PropertyTab類,下面是MSDN中的描述:

為屬性頁籤提供基類

PropertyTab 類為屬性頁籤提供基類行為。屬性頁籤顯示在“屬性視窗”的 PropertyGrid 控件的工具欄上,并且允許元件顯示其屬性或其他資料的不同視圖。

使用者代碼通常不會直接建立 PropertyTab 的執行個體。而可以将一個 PropertyTabAttribute(它訓示為某一元件顯示的一個或多個屬性頁籤的類型)與應該顯示 PropertyTab 的屬性或類型相關聯。

PropertyGrid 将執行個體化一個與所浏覽元件的類型或屬性字段關聯的 PropertyTabAttribute 所指定類型的 PropertyTab。

  很顯然,我們建立頁籤就是要以它為基類。看一下他的成員,還好,比較簡單,隻有四個屬性,其中有一個Bitmap,是用來設定頁籤的圖示的,一個是TabName,很明顯是頁籤名稱,還有一個GetProperties方法,非常的重要,擷取指定元件的屬性資訊集合,傳回的是PropertyDescriptorCollection類型,很顯然他是一個PropertyDescriptor的集合。請記住這三個成員,後面會有用到的。

    既然傳回了PropertyDescriptor,我們就來看一看它,PropertyDescriptor類是描述屬性資訊的一個類,接着看,看PropertyDescriptor是如何描述屬性資訊的,MSDN中這樣描述的:

      屬性的說明由名稱、其特性、與該屬性關聯的元件類和該屬性的類型組成。

      PropertyDescriptor 提供以下屬性和方法:

  Converter 包含此屬性的 TypeConverter。

  IsLocalizable 訓示該屬性是否應該本地化。

  GetEditor 傳回指定類型的編輯器。

      PropertyDescriptor 還提供以下 abstract 屬性和方法:

  ComponentType 包含該屬性綁定到的元件的類型。

  IsReadOnly 訓示該屬性是否是隻讀的。

  PropertyType 擷取屬性的類型。

  CanResetValue 訓示重置元件是否會更改該元件的值。

  GetValue 傳回元件上屬性的目前值。

  ResetValue 重置元件屬性的值。

  SetValue 将元件的值設定為一個不同的值。

  ShouldSerializeValue 訓示是否需要持久儲存該屬性的值。

      通常,abstract 成員是通過反射實作的。有關反射的更多資訊,請參見 反射 中的主題。

  可見它非常詳細的描述了一個屬性的資訊。而且從中好像看到了很多熟悉的東西,類型轉換,指定編輯器,設計時序列化,是的,在前面幾篇文章中介紹的一些功能,其實在内部就是通過這個類來實作的。

  再重新仔細看一下PropertyGrid類,發現有一個SelectedGridItem的屬性,傳回的是GridItem類型,MSDN如是說:

    每個 GridItem 都對應于 SelectedObject 的一項屬性。

    可以使用傳回的 GridItem 檢視標明對象的類型資訊、PropertyDescriptor、父對象和子對象。

  看一下這個GridItem。MSDN是這樣寫道的:

    實作 PropertyGrid 中的一行。

    網格項将視圖的層次結構表示為 PropertyGrid。可以使用 GridItem 擷取關于網格狀态和内容的資訊。

    不應緩存 GridItem 對象,因為它們表示通路它們時 PropertyGrid 的狀态的快照,而且網格活動可能釋放它們。PropertyGrid 經常内部重新建立 GridItem 對象,而不更改呈現給使用者的視圖。

  也就是說PropertyGrid的視圖是由一個一個GridItem壘起來的,而且隻是狀态的快照,你在改變屬性排序,展開,折疊等的時候,PropertyGrid可能就會釋放,建立GridItem。來看一下GridItem的組成,他有一個GridItems屬性,說明GridItem是可以有子項的,也就是屬性中的子屬性;還有一個PropertyDescriptor屬性,就是上面PropertyTab中GetProperties傳回來的類型,他用來描述與此GridItem相連的屬性的資訊,以便将屬性顯示出來。

  下面這張圖簡單描述PropertyGrid的組成:

  

PropertyGrid—添加屬性Tab

  從以上的分析,大緻可以看出PropertyGrid是如何工作的,當把某一對象指派給PropertyGrid的SelectedObject屬性時,PropertyGrid通知選中的PropertyTab,PropertyTab通過他的GetProperties方法,擷取并傳回這個對象的一個屬性資訊集合(PropertyDescriptorCollection),PropertyGrid擷取到這個集合後,分析其内容,為集合中的每個元素(每個屬性)建立一個GridItem,并将GridItem組織起來顯示出來,也就是我們所看到的屬性内容了。

  由此可見,我們對屬性的操作是通過GridItem進行的,而GridItem又通過PropertyDescriptor來對屬性進行操作,在PropertyDescriptor中會看到很多我們之前見到過的東西,如類型轉換,屬性編輯器,屬性設計時序列化等,其實這些都是通過PropertyDescriptor來實作的(詳情可見MSDN)。

  了解了PropertyGrid的組成後,再來添加頁籤就很清晰了。首先我們知道要建立一個頁籤類,并且要繼承于PropertyTab。重寫PropertyTab的TabName和Bitmap屬性,用來設定頁籤的外觀和名字;重寫GetProperties方法,來設定我們這個頁籤中要顯示哪些屬性,隻需傳回一個我們要顯示的屬性的PropertyDescriptorCollection,至于後面建立GridItem和顯示的工作就交給PropertyGrid自己去完成就行了。

  下面舉個例子:同樣的,假如我們有一個控件類:

 MyControl

  控件類有一個Angle的屬性,以及它從UerControl繼承過來的很多屬性,在VS的屬性框中會全部的顯示出來,如果現在我們隻需要顯示在“角度”這一分類中的([Category("角度")])屬性。我們建立一個頁籤類,讓他隻顯示“角度”這一分類中的屬性。

 MyPropertyTab

可見我們重寫了GetProperties方法,該方法從對象的屬性中篩選出“角度”類屬性;重寫了TabName,讓其為AngleProperty;重寫Bitmap,是頁籤的圖示,這裡是從字元串中擷取的位圖,也可以從項目資源中擷取。

  設計好頁籤後,如何讓它出現在PropertyGrid中呢,有兩種方法:

  1. 如果這個頁籤隻是針對我們一個特定的類,就如上面那個例子,頁籤顯示“角度”類型屬性,并不是所有的類都有“角度”屬性,頁籤隻對有“角度”的類型有意義,那麼,我們就讓它在選中了那樣的類型時才顯示,不然就不顯示,怎麼做呢,很簡單,隻需要給那樣的類(有“角度”屬性的類)添加一個特性:PropertyTab特性,例如在我們的MyControl類型上加上

  [PropertyTabAttribute(typeof(MyPropertyTab), PropertyTabScope.Component)]

  第一個參數中是我們自己定義的頁籤類,注意這裡第二個參數使用的是 PropertyTabScope.Component,它表明隻對這種類型的屬性使用MyPropertyTab頁籤。PropertyTabScope.Document表明隻要在此文檔中,屬性頁籤就一直顯示(MSDN中說得,一直不太明白什麼意思)。其他兩個不能使用。

  2. 如果這個頁籤是針對所有類型的,他需要一直顯示,那麼我們就直接把他加到我們的PropertyGrid控件中。上面說了PropertyGrid有個PropertyTabs的屬性,将我們自定義的頁籤類添加到這個集合中即可,例如:

  this.propertyGrid1.PropertyTabs.AddTabType(typeof(MyPropertyTab));

  當然,這樣添加後,他針對所有的類型的對象都有效,就不需要再給特定的類添加PropertyTab特性了。

  本例中,我們使用第一種方法,添加PropertyTab特性。即在我們定義的MyControl類上加上[PropertyTabAttribute(typeof(MyPropertyTab), PropertyTabScope.Component)]。好了,下面讓我們來看一下效果:

PropertyGrid—添加屬性Tab

  可見我們自定義的頁籤顯示在PropertyGrid中了,而且隻顯示了“角度”類屬性。

  以下是完整的代碼:

 完整代碼

  建立Windows工程,添加該檔案,将我們的MyControl控件拖入Form中,選中控件,看我們定義的tab是否出現,再選擇Form,看是否消失。

  根據本文方法,我們可以建立各種自定義屬性頁籤,顯示的内容關鍵在于你的GetProperties函數傳回什麼樣的值。

  當然,全文純屬個人愚見,錯誤荒謬之處,還望指出,不甚感激!

沒有整理與歸納的知識,一文不值!高度概括與梳理的知識,才是自己真正的知識與技能。 永遠不要讓自己的自由、好奇、充滿創造力的想法被現實的架構所束縛,讓創造力自由成長吧! 多花時間,關心他(她)人,正如别人所關心你的。理想的騰飛與實作,沒有别人的支援與幫助,是萬萬不能的。

    本文轉自wenglabs部落格園部落格,原文連結:http://www.cnblogs.com/arxive/p/6287063.html,如需轉載請自行聯系原作者