zoukankan      html  css  js  c++  java
  • PropertyGrid—属性类别排序

     属性默认按照字母顺序排序,有时,我们想要按自定义的顺序排序

    这个工具类可以把每个属性类别里的属性排序,但是不能把属性类别排序。

    为属性类添加属性:[TypeConverter(typeof(PropertySorter))]
    为每个属性添加属性:[PropertyOrder(10)]

    private void Form_Load(object sender, EventArgs e)
    {
        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
    }

      属性排序方式

      属性的排序是基于容器类的.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类`````````````````````````````````````````````````````````````````````````````````````````````//型。至此,排序功能圆满完成。
            }
    ...
    
    }

    参考

    1. PropertyGrid排序

    2. PropertyGrid控件 分类(Category)及属性(Property)排序

    3. Ordering Items in the Property Grid

  • 相关阅读:
    MVC5+EF6 入门完整教程七
    MVC5+EF6 入门完整教程六
    MVC5+EF6 入门完整教程五
    MVC5+EF6 入门完整教程四
    MVC5 + EF6 完整入门教程三
    MVC5 + EF6 入门完整教程二
    MVC5 + EF6 入门完整教程
    最短路径简析
    PAT 1147 Heaps
    PAT 1146 Topological Order
  • 原文地址:https://www.cnblogs.com/code1992/p/10197534.html
Copyright © 2011-2022 走看看