這個工具類可以把每個屬性類別里的屬性排序,但是不能把屬性類別排序。
為屬性類添加屬性:[TypeConverter(typeof(PropertySorter))]
為每個屬性添加屬性:[PropertyOrder(10)]
{
propertyGrid1.SelectedObject = new Person();
}
[TypeConverter( typeof(PropertySorter))]
[DefaultProperty( " Name ")]
public class Person
{
protected const string PERSONAL_CAT = " Personal Details ";
private string _name = " Bob ";
private DateTime _birthday = new DateTime( 1975, 1, 1);
[Category(PERSONAL_CAT), PropertyOrder( 10)]
public string Name
{
get { return _name;}
set {_name = value;}
}
[Category(PERSONAL_CAT), PropertyOrder( 11)]
public DateTime Birthday
{
get { return _birthday;}
set {_birthday = value;}
}
[Category(PERSONAL_CAT), PropertyOrder( 12)]
public int Age
{
get
{
TimeSpan age = DateTime.Now - _birthday;
return ( int)age.TotalDays / 365;
}
}
}
工具類
// (C) Paul Tingey 2004
//
using System;
using System.Collections;
using System.ComponentModel;
namespace OrderedPropertyGrid
{
public class PropertySorter : ExpandableObjectConverter
{
#region Methods
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
{
return true;
}
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
{
//
// This override returns a list of properties in order
//
PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(value, attributes);
ArrayList orderedProperties = new ArrayList();
foreach (PropertyDescriptor pd in pdc)
{
Attribute attribute = pd.Attributes[ typeof(PropertyOrderAttribute)];
if (attribute != null)
{
//
// If the attribute is found, then create an pair object to hold it
//
PropertyOrderAttribute poa = (PropertyOrderAttribute)attribute;
orderedProperties.Add( new PropertyOrderPair(pd.Name,poa.Order));
}
else
{
//
// If no order attribute is specifed then given it an order of 0
//
orderedProperties.Add( new PropertyOrderPair(pd.Name, 0));
}
}
//
// Perform the actual order using the value PropertyOrderPair classes
// implementation of IComparable to sort
//
orderedProperties.Sort();
//
// Build a string list of the ordered names
//
ArrayList propertyNames = new ArrayList();
foreach (PropertyOrderPair pop in orderedProperties)
{
propertyNames.Add(pop.Name);
}
//
// Pass in the ordered list for the PropertyDescriptorCollection to sort by
//
return pdc.Sort(( string[])propertyNames.ToArray( typeof( string)));
}
#endregion
}
#region Helper Class - PropertyOrderAttribute
[AttributeUsage(AttributeTargets.Property)]
public class PropertyOrderAttribute : Attribute
{
//
// Simple attribute to allow the order of a property to be specified
//
private int _order;
public PropertyOrderAttribute( int order)
{
_order = order;
}
public int Order
{
get
{
return _order;
}
}
}
#endregion
#region Helper Class - PropertyOrderPair
public class PropertyOrderPair : IComparable
{
private int _order;
private string _name;
public string Name
{
get
{
return _name;
}
}
public PropertyOrderPair( string name, int order)
{
_order = order;
_name = name;
}
public int CompareTo( object obj)
{
//
// Sort the pair objects by ordering by order value
// Equal values get the same rank
//
int otherOrder = ((PropertyOrderPair)obj)._order;
if (otherOrder == _order)
{
//
// If order not specified, sort by name
//
string otherName = ((PropertyOrderPair)obj)._name;
return string.Compare(_name,otherName);
}
else if (otherOrder > _order)
{
return - 1;
}
return 1;
}
}
#endregion
}
url:http://greatverve.cnblogs.com/archive/2012/02/08/propergrid-order.html
參考:http://www.codeproject.com/KB/cs/orderedpropertygrid.aspx
參考:
屬性排序方式
屬性的排序是基於容器類的.sort();實現的。因為控件通過TypeConverter.GetProperties();方法獲得PropertyDescriptorCollection類型的對象。並根據此對象的元素設定SelectedObject的表現方式等。故實現屬性類的排序首先需要獲得對象的集合,然后使其按指定方式排序。因為sort()方法接受string[]類型的參數作為排序依據,其相對於屬性的排序是比對其Name屬性(或DisplayName屬性),而我們需要在保證本地化的前提下完成排序,所以我們要在拋開其Name屬性(或者DisplayName)的前提下實現排序(理論上我們能獲得屬性property的name屬性,即方法名,但是筆者在實踐中設定字符串數組中依次填入name作為排序依據,未能成功,非本地化的情況下可以實現,現在仍未找到原因,猜測其可能會以DisplayName替代Name返回???)。基於以上分析與原因,我們需要給每個屬性Property添加一個屬性Attribute可以作為排序的依據。到此,存在一個問題。如何根據新的屬性(代稱為order)對Property進行排序。較為優雅的方法是實現IComparable()接口。
事例代碼如下:(部分代碼來源於網絡,感謝先輩)
[AttributeUsage(AttributeTargets.Property)]
public class PropertyOrderAttribute : Attribute//自定義Attribute類,向property提供
```````````````````````````````````````````````````//order屬性
{
private int order;
public PropertyOrderAttribute(int order)
{
this.order = order;
}
public int Order
{
get
{
return order;
}
}
}
class TestPropertyDescriptor : PropertyDescriptor,IComparable//繼承PropertyDescriptor類並實現IComparable接口
{
private PropertyDescriptor basePropertyDescriptor;
private int order;
...
//構造函數
public TestPropertyDescriptor(PropertyDescriptor basePropertyDescriptor): base(basePropertyDescriptor)
{
this.basePropertyDescriptor = basePropertyDescriptor;
order = GetOrder(basePropertyDescriptor.Attributes);
}
//獲得property的order屬性
private int GetOrder(AttributeCollection ac)
{
foreach (Attribute a in ac)
{
if (a is PropertyOrderAttribute)
return ((PropertyOrderAttribute)a).Order;
}
return 0;
}
...
#region "IComparable"
public int CompareTo(object tpd)//實現接口,使此類的對象可以依據order進行比較、排序
{
TestPropertyDescriptor other = (TestPropertyDescriptor)tpd;
if (order == other.order) return string.Compare(Name, other.Name);
else return (order > other.order) ? 1 : -1;
}
#endregion
}
class ICustomTDClass1: Class1 , ICustomTypeDescriptor//Class1為需要對其屬性進行排序的自定義類。
{
...
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
PropertyDescriptorCollection tmpPDC = TypeDescriptor.GetProperties(typeof(ICustomTDClass1), attributes);
PropertyDescriptorCollection result = new PropertyDescriptorCollection(null);
ArrayList orderPdList = new ArrayList();
foreach (PropertyDescriptor pd in tmpPDC)
{
TestPropertyDescriptor tpd = new TestPropertyDescriptor(pd);
result.Add(tpd);
orderPdList.Add(tpd);
}
orderPdList.Sort();//根據order排序
ArrayList propertyNames = new ArrayList();
foreach (TestPropertyDescriptor propertyAttributes in orderPdList)//獲得排序后的DisplayName數組
{
propertyNames.Add(propertyAttributes.DisplayName);
}
return result.Sort((string[])propertyNames.ToArray(typeof(string)));//根據數組對結果排序,注意這里不能直接return `````````````````````````````````````````````````````````````````````````````````````````````//result.Sort(),因為在result里存着的是PropertyDescriptor類`````````````````````````````````````````````````````````````````````````````````````````````//型的對象,而不是我們定義的TestPropertyDescriptor類`````````````````````````````````````````````````````````````````````````````````````````````//型。至此,排序功能圓滿完成。
}
...
}
PS:並不是所有待排序的類都要重寫ICustomTypeDescriptor,更加簡潔的方法是自定義TypyConverter類,並在其中的GetProperties(........){}中實現(不是GetProperties(){})。再次感謝先輩們。