1、前言
現在搜尋PropertyGuid,發現的一些文檔,特別是在百度文庫中,都是互相抄,我發現最初的文檔在這兒http://msdn.microsoft.com/en-us/library/aa302326.aspx。這裡面也有一些錯誤,看的時候注意辨別一下。
2、目標:以最少的代碼,實現在GUI中配置下列結構的對象。
namespace WindowsFormsApplication1{ public partial class Form1 : Form { public Form1() { InitializeComponent(); } private Database database = new Database(); }}
這個database對象就是待配置的對象,下面是Database類的結構:
public class Database{ public string Name { get; set; } public string Password { get; set; } public string InitializeCommand { get; set; } public List<Table> Tables { get; set; }}
下面是Table類的結構:
public class Table{ public string Name { get; set; } public List<Column> Columns { get; set; } public string Comment { get; set; }}
下面是Column類的結構:
public class Column{ public string Name { get; set; } public SupportedType Type { get; set; } public string Comment { get; set; } public bool IsMainKey { get; set; } public bool NotNull { get; set; } public bool IsAutoIncrement { get; set; } public bool IsIndex { get; set; }}
下面是SupportedType的結構:
public enum SupportedType{ Boolean, DateTime, Decimal, Double, Int64, Int32, Int16, SByte, Single, String, UInt64, UInt32, UInt16, Byte}
這裡的例子用了大家都熟悉的資料庫結構的模型,方便理解。
這裡完成之後,向介面拖入Property控制項,並把database欄位賦給控制項的SelectedObject屬性,運行一下,得到以下效果:
點擊...,得到以下效果:
點擊“添加”,再點擊...,得到以下效果:
可以注意到我並沒有寫多少代碼,就完成的大部分的效果,和Visual Studio的屬性視窗十分類似。但是,這個不美觀,也有BUG,下面開始改善一下這些效果。
首先介紹一些在使用PropertyGrid控制項時常用的Attribute(至於Attribute是什麼,自行搜尋之):
1)在屬性框被點擊後,游標自動跳到一個屬性的框中:DefaultProperty,附著在類上,參數是屬性的名稱;
2)當值改變時,變成粗體的效果:DefaultValue,附著在屬性上,參數是非粗體時的值;(注意這個不會決定預設值,這個決定粗體效果。)
3)對屬性分類:Category,附著在屬性上,參數是類別名稱;
4)唯讀,不可編寫,變灰色:ReadOnly,附著在屬性上,參數是false或true,不加此Attribute的效果是此值為false的效果;
5)顯示的名稱,設定後不再顯示為屬性的名稱:DisplayName,附著在屬性上,參數是顯示的名稱;
6)描述資訊,在描述框裡顯示:Description,附著在屬性上,參數是描述資訊;
7)是否顯示:Browsable,附著在屬性上,參數為false或true,不加此Attribute的效果是此值為true的效果。
以下是一些經驗:
8)每個項都寫成自動屬性的形式;
9)在建構函式中對每一個值都儘可能賦值,這個也決定了預設值。沒有這一步,可能造成設定後無法儲存的BUG;
一般:string類型可以初始化為string.empty,bool類型不必初始化,List先判斷是否為null,如果為null,初始化一下。
10)可以被正確識別的對象:各種實值型別、String、數組、DateTime、TimeSpan、Point、Size、Font、Color、枚舉類型、Image、Bitmap、Metafile、Icon、Cursor、List<T>。
下面是最佳化後的代碼,都在這兒了:
public partial class Form1 : Form{ public Form1() { InitializeComponent(); propertyGrid1.SelectedObject = database; } private readonly Database database = new Database();}
[DefaultProperty("Tables")]public class Database{ public Database() { Name = "NewDatabase"; Password = string.Empty; InitializeCommand = string.Empty; if (Tables == null) { Tables = new List<Table>(); } } [Category("屬性"), DisplayName("資料庫名稱")] public string Name { get; set; } [Category("屬性"), DisplayName("資料庫密碼")] public string Password { get; set; } [Category("屬性"), DisplayName("初始化語句")] public string InitializeCommand { get; set; } [Category("資料表設定"), DisplayName("資料表集合")] public List<Table> Tables { get; set; }}
[DefaultProperty("Columns")]public class Table{ public Table() { Name = "NewTable"; Comment = string.Empty; if (Columns == null) { Columns = new List<Column>(); } } [Category("屬性"), DisplayName("資料表名稱")] public string Name { get; set; } [Category("資料列設定"), DisplayName("資料列集合")] public List<Column> Columns { get; set; } [Category("屬性"), DisplayName("備忘")] public string Comment { get; set; }}
[DefaultProperty("Name")]public class Column{ public Column() { Name = "NewColumn"; Type = SupportedType.Int32; Comment = string.Empty; NotNull = true; } [DisplayName("列名"), Category("屬性")] public string Name { get; set; } [DisplayName("類型"), Category("屬性")] public SupportedType Type { get; set; } [DisplayName("注釋"), Category("屬性")] public string Comment { get; set; } [DisplayName("是否是主鍵"), DefaultValue(false), Category("屬性")] public bool IsMainKey { get; set; } [DisplayName("是否非空"), DefaultValue(true), Category("屬性")] public bool NotNull { get; set; } [DisplayName("是否自動成長"), DefaultValue(false), Category("屬性")] public bool IsAutoIncrement { get; set; } [DisplayName("是否是索引"), DefaultValue(false), Category("屬性")] public bool IsIndex { get; set; }}
下面是最佳化後的效果:
3、遺留的問題
1)點擊右上方的問號,沒反應;
2)如果不是最頂層,就沒有Description欄;
3)除了之前提到的一些類型,其它的類都不能自動使用上。
上述問題需要增加自訂的代碼來解決,不符合本文“使用儘可能少的代碼”的主題,相關的擴充心得會在之後的博文中表述出來。
4、更新
PropertyGrid is the exact same control as used in the Visual Studio Properties window. Where it is pretty useful to edit the properties of various Winforms class objects that you use in the designer. That's because Microsoft did a lot of work to provide the classes that convert a class object to a string. A custom TypeConverter class, like the ColorConverter class. And a custom editor for the property, were desired. A custom UITypeEditor, like the AnchorEditor class, the one that gives the Anchor property the special dropdown that lets you click the bars.
But when you display your own class object in a PropertyGrid then those goodies are missing. Unless you create your own TypeConverter and UITypeEditor classes. Right now you are just getting the default ones. Which are not very useful, as you noted in your question.
Beware of the cost of writing those classes, they have a fairly steep learning curve. Which is very rarely worth the hassle, especially since a PropertyGrid isn't exactly the friendliest user interface for a non-programmer. Just creating your own Form class is almost always the better bang for the buck.
由此,我應該不會在此方向繼續研究了。
5、更新
在類中override ToString方法可以解決在listbox中顯示錯誤的問題。