提供可交互的屬性視圖 當你在Visual C#
NET中創建一個項目的時候
你可能會注意到屬性窗口的工具欄上有一個像閃電的按鈕
按下這個按鈕屬性窗口就會切換到事件視圖
這樣就可以來編輯事件處理了
屬性窗口的視圖來自
屬性頁(Property Tabs)
因此視圖使用的最主要的類是PropertyTab
命名空間是System
Windows
Forms
Design
一個屬性頁可以和一個特別的組件
設計文檔關聯起來
或者是可以使用的靜態關聯
和組件或文檔關聯起來的屬性頁在類上用PropertyTabAttribute特性來指定
這個特性指定要創建的Tab的類型
它在屬性窗口上是否顯示由PropertyTabAttribute的PropertyTabScope參數來指定
指定為Component范圍的屬性頁的可見性由有PropertyTabAttribute特性的組件的可見性來決定
Document范圍的屬性頁則可以在當前項目的設計中都可見
他的默認值是PropertyTabScope
Component
舉一個例子來說
看看
FunkyButton
項目
FunkyButton是一個擴展了PropertyTab的UserControl
而且可以讓我們把控件定為不規則的多邊形
圖
FunkyButton
當前選擇的屬性頁就是屬性窗口從被選擇的控件的屬性中得到的
屬性頁因此就允許來操縱顯示屬性的不同集合
Events頁就是像屬性一樣以某種方式來處理事件
在這個例子中
屬性頁就創建了表示控件頂點的屬性
NET framework中的屬性用PropertyDescriptor類來封裝
PropertyDescriptor本身是一個抽象類
framework中由他派生的類提供了訪問組件的開放屬性的方法
不過
屬性窗口是直接作用在PropertyDescriptor上
而不是直接作用在屬性上
因此
我們就可以寫自己的PropertyDescriptor來做一些特殊的工作
在這個例子裡
我們就有一個屬性表示控件的頂點數
另一個就表示每一個頂點
再次注意一下
我們在屬性窗口上增加頁並不相應的作用在其他對象上
當屬性窗口向PropertyTab詢問Properties的時候
它就調用GetProperties方法
對於我們的示例程序
這個方法就像下面的一樣
public override PropertyDescriptorCollection
GetProperties(ITypeDescriptorContext context
object component
Attribute[] attrs)
{
// our list of props
//
ArrayList propList = new ArrayList();
// add the property for our count of vertices
//
propList
Add(new NumPointsPropertyDescriptor(this));
// add a property descriptor for each vertex
//
for (inti =
; i < ((FunkyButton)component)
Points
Count; i++)
{
propList
Add(new VertexPropertyDescriptor(this
i));
}
// return the collection of PropertyDescriptors
PropertyDescriptor[] props =
(PropertyDescriptor[])propList
ToArray(typeof(PropertyDescriptor));
return new PropertyDescriptorCollection(props);
}
GetProperties僅僅是返回一些屬性描述的集合
PropertyDescriptors是相當的簡單
仔細查看這些代碼以了解他們是怎麼工作的
FunkyButton同時示例了下拉列表編輯器的實現
對於每一個點
我們不是簡單的輸入坐標的X和Y值
我們會圖示FunkyButton的形狀
而且可以用圖形化的方法改變點的位置
這樣設置的編輯樣式更加地友好
圖
圖形化的點向量
由於訂制的PropertyTab提供了屬性
重載這個屬性的編輯器也是很容易的
只要簡單地重載PropertyDescriptor的GetEditor方法
然後返回訂制組件的實例就可以了
public override object GetEditor(Type editorBaseType)
{
// make sure we
re looking for a UITypeEditor
//
if (editorBaseType == typeof(System
Drawing
Design
UITypeEditor))
{
// create and return one of our editors
//
if (editor == null)
{
editor = new PointUIEditor(owner
target);
}
return editor;
}
return base
GetEditor(editorBaseType);
}
設計編輯器同樣簡單
編輯器就是一個簡單的UserControl
所以我們就可以像設計其他的windowsForms對象一樣來做
圖
Designing the editor
最後
當用戶在屬性窗口中點擊下拉箭頭時
我們的編輯器就可以將剛才創建UI編輯器彈出來了
PointUIEditor中的UITypeEditor
EditValue重載後就可以實現了
public override object EditValue(
ITypeDescriptorContext context
IServiceProvider sp
object value)
{
// get the editor service
IWindowsFormsEditorService edSvc =
(IWindowsFormsEditorService)sp
GetService(typeof(IWindowsFormsEditorService));
// create our UI
if (ui == null)
{
ui = new PointEditorControl();
}
// initialize the ui with the settings for this vertex
ui
SelectedPoint = (Point)value;
ui
EditorService = edSvc;
ui
Target = (FunkyButton)context
Instance;
// instruct the editor service to display the control as a
// dropdown
edSvc
DropDownControl(ui);
// return the updated value;
return ui
SelectedPoint;
}
我們同樣可以使用它 在你自己的應用中可以擁有和IDE屬性窗一樣的特性
把System
Windows
Forms
PropertyGrid的控件
添加到IDE中的ToolBox中
通過獲取在ToolBox的Component標簽裡的PropertyGrid
PropertyGrid和其他的控件工作是一樣的
你可以anchor或者是Dock他
改變它的色彩等
下面的列表列出了PropertyGrid的一些有趣的屬性
這些屬性都可以在設計時設置
在運行時
可以操作PropertyGrid讓他顯示的你的對象
下面是顯示一個button的例子
在這個例子中
PorpertyGrid的幫助和toolbox都被隱藏了
就像上面提到的
你可以設置他自己的屬性
圖
隱藏了toolbar和幫助信息的PropertyGrid
結論 NET framework和Visual Studio
NET給屬性窗口增加了相當多的功能
由於屬性窗口是RAD的核心
這些特性可以在保持易用性的同時有很多的擴展
也因此在Visual Basic中用的很普遍
就像可以在我們的程序中使用PropertyGrid
我們可以把更多的時間放在如何寫好程序上
從而簡化我們的UI工作
下面的代碼是我實現的關於PointF的類型轉換
如果是自定義類型
構造方式完全一樣
在重載時最關鍵的地方就是GetPropertys的實現
不能直接返回基類的方法
否則
子屬性的值是修改不了的
必須返回TypeDescriptor的GetPropertys
至於為什麼
請自行查閱MSDN上相關文章的介紹
#region PointF的轉換類實現
/// <summary>
/// PointF的轉換類實現
/// </summary>
internal sealed class PointFConverter : TypeConverter
{
/// <summary>
/// 重載TypeConverter的CanConvertFrom方法
/// </summary>
/// <param name=
context
></param>
/// <param name=
sourceType
></param>
/// 要測試的目標類型
/// <returns></returns>
public override bool CanConvertFrom(ITypeDescriptorContext context
Type sourceType)
{
if (sourceType == typeof(string)) //sourceType的類型是Type
{
return true;
}
return base
CanConvertFrom(context
sourceType);
}
/// <summary>
/// 重載TypeConverter的ConvertFrom方法
/// 定義從源類型到目標類型的轉換算法
/// </summary>
/// <param name=
context
></param>
/// <param name=
culture
></param>
/// 本地化參數
/// <param name=
value
></param>
/// 輸入字串
/// <returns></returns>
public override object ConvertFrom(ITypeDescriptorContext context
CultureInfo culture
object value)
{
if (value is string) //value是類型實例
{
string[] v = ((string)value)
Split(new char[] {
});
return new PointF
From:http://tw.wingwit.com/Article/program/net/201311/12720.html