Search code examples
c#winformssortingpropertygrid

PropertyGrid Sort By Index


I am displaying a Collection as an expandable object. I only have the options of sorting alphabetically, or not at all.

Alphabetically turns out as such:

Alphabetical Sorting

No Sort turns out as such:

No sorting

I am trying to find a way to sort the collection by index, so it will look like

[0], [1], [2], [3], ..., [9], [10], [11], [12], [13], [14].

I haven't been able to find a reliable way to do this. I did find a solution here, but they use ListItemDescriptor, which doesn't seem to exist.

This is my customertypeconverter, how I have the collection in the object that is in the propertygrid, and the customeditor.

The custom editor just forces it to be expandable only, instead of giving the user the option to open the default editor and add more items.

This is for UserData instead of MarkData, I have done all the work towards UserData, but I used the images for MarkData because it is a smaller collection and made for easier images.

internal class UserDataCollectionConverter : ExpandableObjectConverter
{
    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destType)
    {
        if (destType == typeof(string) && value is UserDataCollection)
        {
            return "User Data";
        }
        return base.ConvertTo(context, culture, value, destType);
    }
}

Object

[EditorAttribute(typeof(UserDataEditor), typeof(UITypeEditor))]
[DescriptionAttribute("Custom user data."),
TypeConverter(typeof(UserDataCollectionConverter)),
CategoryAttribute("Custom")]
public UserDataCollection UserData
{
    get { return _userData; }
    set { _userData = value; }
}

Custom Editor

class UserDataEditor : System.ComponentModel.Design.CollectionEditor    
{
    public UserDataEditor(Type type)
    : base(type)
    {

    }

    public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)   
    {
    UserDataCollection things = new UserDataCollection();           
    return value;
    }
}

UserDataCollection

using System;
using System.Collections;
using System.ComponentModel;

namespace CMS.LaserGraf.Data
{
    public class UserDataCollection : CollectionBase, ICustomTypeDescriptor
    {
        #region

        public void Add(string value)
        {
            this.List.Add(value);
        }

        public void Add(int number)
        {
            for (int i = 0; i < number; i++)
            {
                this.List.Add("");
            }
        }

        public void Remove(string value)
        {
            this.List.Remove(value);
        }

        public void set(string[] values)
        {
            this.List.Clear();
            foreach (string s in values)
            {
                this.List.Add(s);
            }
        }

        public string[] getUserDataArray()
        {
            int i = 0;
            string[] retval = new string[this.List.Count];
            foreach (string s in this.List)
            {
                retval[i++] = s;
            }

            return retval;
        }

        public string this[int index]
        {
            get
            {
                return (string)this.List[index];
            }
            set
            {
                this.List[index] = value;
            }
        }

        #endregion

        // Implementation of interface ICustomTypeDescriptor 
        #region ICustomTypeDescriptor impl

        public String GetClassName()
        {
            return TypeDescriptor.GetClassName(this, true);
        }

        public AttributeCollection GetAttributes()
        {
            return TypeDescriptor.GetAttributes(this, true);
        }

        public String GetComponentName()
        {
            return TypeDescriptor.GetComponentName(this, true);
        }

        public TypeConverter GetConverter()
        {
            return TypeDescriptor.GetConverter(this, true);
        }

        public EventDescriptor GetDefaultEvent()
        {
            return TypeDescriptor.GetDefaultEvent(this, true);
        }

        public PropertyDescriptor GetDefaultProperty()
        {
            return TypeDescriptor.GetDefaultProperty(this, true);
        }

        public object GetEditor(Type editorBaseType)
        {
            return TypeDescriptor.GetEditor(this, editorBaseType, true);
        }

        public EventDescriptorCollection GetEvents(Attribute[] attributes)
        {
            return TypeDescriptor.GetEvents(this, attributes, true);
        }

        public EventDescriptorCollection GetEvents()
        {
            return TypeDescriptor.GetEvents(this, true);
        }

        public object GetPropertyOwner(PropertyDescriptor pd)
        {
            return this;
        }


        public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            return GetProperties();
        }

        public PropertyDescriptorCollection GetProperties()
        {
            // Create a collection object to hold property descriptors
            PropertyDescriptorCollection pds = new PropertyDescriptorCollection(null);

            // Iterate the list of ProcessCounters
            for (int i = 0; i < this.List.Count; i++)
            {
                // Create a property descriptor for the ProcessCounter item and add to the property descriptor collection
                UserDataCollectionPropertyDescriptor pd = new UserDataCollectionPropertyDescriptor(this, i);
                pds.Add(pd);
            }
            // return the property descriptor collection
            return pds;
        }

        #endregion
    }
}

Solution

  • It seems you are already adding in a specific order as seen in below code

    // Iterate the list of ProcessCounters
    for (int i = 0; i < this.List.Count; i++)
    {
        // Create a property descriptor for the ProcessCounter item and add to the property descriptor collection
        UserDataCollectionPropertyDescriptor pd = new UserDataCollectionPropertyDescriptor(this, i);
        pds.Add(pd);
    }
    

    You could achieve sorting in two ways.

    1. You could sort the UserDataCollectionPropertyDescriptor while adding into the PropertyDescriptorCollection in GetProperties()method.
    2. Implement custom PropertyDescriptorCollection class and override the Sort(IComparer comparer) method and pass in your custom comparer for comparing UserDataCollectionPropertyDescriptor.

    Sample Code

    public class UserDataPropertyDescriptorCollection : PropertyDescriptorCollection
    {
    
        public override PropertyDescriptorCollection Sort(IComparer comparer)
        {
            UserDataComparer customComparer = new UserDataComparer();
            return base.Sort(customComparer);
        }
    }
    
    public class UserDataComparer : IComparer
    {
        #region IComparer Members
    
        int IComparer.Compare(object x, object y)
        {
            //cast and compare UserDataCollectionPropertyDescriptor index values
        }
    
        #endregion
    }