This project has moved. For the latest updates, please go here.

Expandable collection using ICustomTypeDescriptor

May 31, 2012 at 12:26 AM
Edited May 31, 2012 at 12:27 AM

Hi,

I'm trying to create an expandable list in the property grid by implementing ICustomTypeDescriptor but it doesn't work.

 

public class PropertyGridList<T> : List<T>, ICustomTypeDescriptor
    {
        public AttributeCollection GetAttributes()
        {
            return TypeDescriptor.GetAttributes(this, true);
        }

        public string GetClassName()
        {
            return TypeDescriptor.GetClassName(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()
        {
            return TypeDescriptor.GetEvents(this, true);
        }

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

        public PropertyDescriptorCollection GetProperties()
        {
            var pds = new PropertyDescriptorCollection(null);

            for (int i = 0; i < Count; i++)
            {
                pds.Add(new ListPropertyDescriptor<T>(this, i, i.ToString()));
            }

            return pds;
        }

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

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

 

and propertydescriptor:

 

public class ListPropertyDescriptor<T> : PropertyDescriptor
    {
        private PropertyGridList<T> _list;
        private int _index;
        public ListPropertyDescriptor(PropertyGridList<T> list, int index, string name)
            : base(name, null)
        {
            _list = list;
            _index = index;
        }

        public override bool CanResetValue(object component)
        {
            return true;
        }

        public override object GetValue(object component)
        {
            return _list[_index];
        }

        public override void ResetValue(object component)
        {
        }

        public override void SetValue(object component, object value)
        {
            _list[_index] = (T)value;
        }

        public override bool ShouldSerializeValue(object component)
        {
            return true;
        }

        public override Type ComponentType
        {
            get { return _list.GetType(); }
        }

        public override bool IsReadOnly
        {
            get { return false; }
        }

        public override Type PropertyType
        {
            get { return _list[_index].GetType(); }
        }
    }

 

 

It works fine for other property grids like the windows forms and WPG, but not this.

Oddly enough if I change the name from i.GetString() to some hardcoded value GetProperties() runs once for each item. Why is this happening?

Jun 1, 2012 at 5:02 PM

Woohoo, I finally got it to work with a typeconverter. Now I have expandable collections that work for ANY type without the need to implement ICustomTypeDescriptor. If anyone needs to know how to do this I'll post the solution.

I found a tiny bug in propertyitem.cs.  In SetPropertyDescriptorProperties the line:

Name = PropertyDescriptor.Name;

According to msdn, Name can only have alphanumeric and underscore chars, and can only start with a letter or underscore and throws an exception otherwise. So it doesnt work if you bind to an array item with a name like "[0]". I've modified it using RegEx to return a proper formatted string.

private void SetPropertyDescriptorProperties()
    {
        
      Name = ConvertStringToAlphaNumericUnderscore(PropertyDescriptor.Name);
      DisplayName = PropertyDescriptor.DisplayName;
      Category = PropertyDescriptor.Category;
      IsReadOnly = PropertyDescriptor.IsReadOnly;
    }

    private string ConvertStringToAlphaNumericUnderscore(string input)
    {
        Regex onlyAlphaNumUscore = new Regex("[^a-zA-Z0-9_]");
        Regex onlyStartingDigits = new Regex("^[0-9]+");

        string result = onlyAlphaNumUscore.Replace(input, "_");

        if (onlyStartingDigits.IsMatch(result))
            result = "_" + result;

        return result;
    }

Hope this helps.

Jul 19, 2012 at 11:31 AM
Edited Jul 20, 2012 at 4:44 AM

Hello codetoad,

  Thanks for your post. It helped me out in certain extend. As you said in your first post, even I was using WPG and was working perfectly. But now I am facing the same issue that you have faced. The problem when I expanded my collection, it just shows the parameter names. Unfortunately i cannot see the properties which I would like to change in the property grid.

ParameterCollection

         Param Name 1   MyNameSpace.MyParameter

         Param Name 2   MyNameSpace.MyParameter

         Param Name 3   MyNameSpace.MyParameter

It displays as given above.... I cannot see the properties of my 'MyParameter' object.

Did you faced any issues like this? If so could you please tell me the solution? (Note: this code was working with WPG and I have the code structure similar to yours and I used 'PropertyDescriptor' too)... Please help....

Thanks in advance.

Jul 19, 2012 at 8:11 PM

Hello CodeToad,

I would be interested in seeing your final solutions.

 

Aug 17, 2012 at 8:50 PM

An issue was created based on this thread.

http://wpftoolkit.codeplex.com/workitem/18484

Aug 28, 2012 at 7:28 AM

Hi CodeToad

 

I was wondering how you managed to do this with typeconverter instead of ICustomTypeDescriptor? I would be very greateful if you gave some hints how to do it.

Apr 4, 2013 at 9:22 PM
Edited Apr 4, 2013 at 9:22 PM
Sorry to bump an old thread. I'm looking into this as well.

http://xkcd.com/979/