Windows Develop Bookmark and Share   
 index > Windows Forms Designer > Implementing ICustomTypeDescriptor for Use at Runtime
 

Implementing ICustomTypeDescriptor for Use at Runtime

Hi,

I am trying to implement the ICustomTypeDescriptor on one of our custom controls, which is just a TextBox. Basically at runtime in my application, I want to show a PropertyGrid for this TextBox control, but I only want certain properties to display. So I am implementing the ICustomTypeDescriptor interface like so below and only including properties that have a certain category defined. This works great, but it seems to mess up the control in design mode. When I add the control to a form and look at the properties in VS, only a few properties display, and they aren't related to my special category properties. An example is "Length" and each property that is shown has the error "Object does not match target type".

How can I get this to work where my implementation of ICustomTypeDescriptor has no effect on the control in design mode?

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

        string ICustomTypeDescriptor.GetClassName()
        {
            return TypeDescriptor.GetClassName(this, true);
        }

        string ICustomTypeDescriptor.GetComponentName()
        {
            return TypeDescriptor.GetComponentName(this, true);
        }

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

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

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

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

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

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

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
        {
            if (!this.DesignMode)
            {
                PropertyDescriptorCollection collection = TypeDescriptor.GetProperties(this, attributes, true);

                PropertyDescriptorCollection newList = new PropertyDescriptorCollection(new PropertyDescriptor[0]);

                foreach (PropertyDescriptor prop in collection)
                {
                    Attribute a = prop.Attributes[typeof(CategoryAttribute)];

                    if (a != null && ((CategoryAttribute)a).Category == "SixDisciplines")
                        newList.Add(prop);
                }

                return newList;
            }
            else
                return TypeDescriptor.GetProperties(attributes);
        }

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
        {
            if (!this.DesignMode)
            {
                PropertyDescriptorCollection collection = TypeDescriptor.GetProperties(this, true);
                PropertyDescriptorCollection newList = new PropertyDescriptorCollection(new PropertyDescriptor[0]);

                foreach (PropertyDescriptor prop in collection)
                {
                    Attribute a = prop.Attributes[typeof(CategoryAttribute)];

                    if (a != null && ((CategoryAttribute)a).Category == "SixDisciplines")
                        newList.Add(prop);
                }

                return newList;
            }
            else
                return TypeDescriptor.GetProperties(this, true);
        }

        object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
        {
            return this;
        }



Thanks,
~Corey
CoLeichty  Wednesday, August 12, 2009 1:54 PM

Hi CoLeichty,

We need to change the code in PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes). We need to call another overload of the TypeDescriptor.GetProperties method to pass the control as a parameter, otherwise it would not be able to know which component we need to get properties from.

This is the modified code snippet:

public class MyTextBox1 : TextBox, ICustomTypeDescriptor 
{
    AttributeCollection ICustomTypeDescriptor.GetAttributes()
    {
        return TypeDescriptor.GetAttributes(this, true);
    }

    string ICustomTypeDescriptor.GetClassName()
    {
        return TypeDescriptor.GetClassName(this, true);
    }

    string ICustomTypeDescriptor.GetComponentName()
    {
        return TypeDescriptor.GetComponentName(this, true);
    }

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

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

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

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

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

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

    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
    {
        if (!this.DesignMode)
        {
            PropertyDescriptorCollection collection = TypeDescriptor.GetProperties(this, attributes, true);

            PropertyDescriptorCollection newList = new PropertyDescriptorCollection(new PropertyDescriptor[0]);

            foreach (PropertyDescriptor prop in collection)
            {
                Attribute a = prop.Attributes[typeof(CategoryAttribute)];

                if (a != null && ((CategoryAttribute)a).Category == "SixDisciplines")
                    newList.Add(prop);
            }

            return newList;
        }
        else
            //The control must be passed to the method.
            return TypeDescriptor.GetProperties(this,attributes,true);
    }

    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
    {
        if (!this.DesignMode)
        {
            PropertyDescriptorCollection collection = TypeDescriptor.GetProperties(this, true);
            PropertyDescriptorCollection newList = new PropertyDescriptorCollection(new PropertyDescriptor[0]);

            foreach (PropertyDescriptor prop in collection)
            {
                Attribute a = prop.Attributes[typeof(CategoryAttribute)];

                if (a != null && ((CategoryAttribute)a).Category == "SixDisciplines")
                    newList.Add(prop);
            }

            return newList;
        }
        else
            return TypeDescriptor.GetProperties(this, true);
    }

    object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
    {
        return this;
    }
}

Let me know if this helps.
Aland Li


Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.
  • Marked As Answer byCoLeichty Friday, August 14, 2009 8:37 PM
  • Unmarked As Answer byCoLeichty Friday, August 14, 2009 8:09 PM
  • Marked As Answer byCoLeichty Friday, August 14, 2009 12:17 PM
  •  
Aland Li  Friday, August 14, 2009 5:50 AM
Aland,

Sorry, I figured it out. The designer apparently wasn't picking up all the changes I was making. I had to do a Clean build and now everything works as expected.


Thanks,
~Corey
  • Marked As Answer byCoLeichty Friday, August 14, 2009 8:37 PM
  •  
CoLeichty  Friday, August 14, 2009 8:37 PM

Hi CoLeichty,

We need to change the code in PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes). We need to call another overload of the TypeDescriptor.GetProperties method to pass the control as a parameter, otherwise it would not be able to know which component we need to get properties from.

This is the modified code snippet:

public class MyTextBox1 : TextBox, ICustomTypeDescriptor 
{
    AttributeCollection ICustomTypeDescriptor.GetAttributes()
    {
        return TypeDescriptor.GetAttributes(this, true);
    }

    string ICustomTypeDescriptor.GetClassName()
    {
        return TypeDescriptor.GetClassName(this, true);
    }

    string ICustomTypeDescriptor.GetComponentName()
    {
        return TypeDescriptor.GetComponentName(this, true);
    }

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

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

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

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

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

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

    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
    {
        if (!this.DesignMode)
        {
            PropertyDescriptorCollection collection = TypeDescriptor.GetProperties(this, attributes, true);

            PropertyDescriptorCollection newList = new PropertyDescriptorCollection(new PropertyDescriptor[0]);

            foreach (PropertyDescriptor prop in collection)
            {
                Attribute a = prop.Attributes[typeof(CategoryAttribute)];

                if (a != null && ((CategoryAttribute)a).Category == "SixDisciplines")
                    newList.Add(prop);
            }

            return newList;
        }
        else
            //The control must be passed to the method.
            return TypeDescriptor.GetProperties(this,attributes,true);
    }

    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
    {
        if (!this.DesignMode)
        {
            PropertyDescriptorCollection collection = TypeDescriptor.GetProperties(this, true);
            PropertyDescriptorCollection newList = new PropertyDescriptorCollection(new PropertyDescriptor[0]);

            foreach (PropertyDescriptor prop in collection)
            {
                Attribute a = prop.Attributes[typeof(CategoryAttribute)];

                if (a != null && ((CategoryAttribute)a).Category == "SixDisciplines")
                    newList.Add(prop);
            }

            return newList;
        }
        else
            return TypeDescriptor.GetProperties(this, true);
    }

    object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
    {
        return this;
    }
}

Let me know if this helps.
Aland Li


Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.
  • Marked As Answer byCoLeichty Friday, August 14, 2009 8:37 PM
  • Unmarked As Answer byCoLeichty Friday, August 14, 2009 8:09 PM
  • Marked As Answer byCoLeichty Friday, August 14, 2009 12:17 PM
  •  
Aland Li  Friday, August 14, 2009 5:50 AM
Aland,

I thought this was working, but now it isn't. My designer no longer has weird errors, but it doesn't seem to be following my this.DesignMode check correctly. When I add this control to the designer and look at the properties, the properties are filtered out just like when I run the program and display a property grid. At runtime I want the properties to be filtered, but at design time I do not. How can I accomplish this? Below is my TestControl. It should be easy for you test out. I am using VS 2008. Just add a PropertyGrid to a windows form and set this control to the grid to see the filtered properties. Then add the TestControl to the form and look at the properties in the designer.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace CustomControls
{
    public class TestControl : TextBox, ICustomTypeDescriptor
    {
        private string _property1;
        private bool _property2;
        private int _property3;

        [Category("SixDisciplines")]
        public string Property1
        {
            get { return _property1; }
            set { _property1 = value; }
        }

        [Category("SixDisciplines")]
        public bool Property2
        {
            get { return _property2; }
            set { _property2 = value; }
        }

        [Category("SixDisciplines")]
        public int Property3
        {
            get { return _property3; }
            set { _property3 = value; }
        }

        #region ICustomTypeDescriptor Members

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

        string ICustomTypeDescriptor.GetClassName()
        {
            return TypeDescriptor.GetClassName(this, true);
        }

        string ICustomTypeDescriptor.GetComponentName()
        {
            return TypeDescriptor.GetComponentName(this, true);
        }

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

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

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

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

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

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

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
        {
            if (!this.DesignMode)
            {
                PropertyDescriptorCollection collection = TypeDescriptor.GetProperties(this, attributes, true);
                PropertyDescriptorCollection newList = new PropertyDescriptorCollection(new PropertyDescriptor[0]);

                foreach (PropertyDescriptor prop in collection)
                {
                    Attribute a = prop.Attributes[typeof(CategoryAttribute)];

                    if (a != null && ((CategoryAttribute)a).Category == "SixDisciplines")
                        newList.Add(prop);
                }

                newList.Add(TypeDescriptor.CreateProperty(typeof(bool), "IsWhere", typeof(bool), null));

                return newList;
            }
            else
                return TypeDescriptor.GetProperties(this, attributes, true);
        }

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
        {
            return TypeDescriptor.GetProperties(this, true);
        }

        object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
        {
            return this;
        }

        #endregion
    }
}
<br/><br/><br/><br/><br/>
CoLeichty  Friday, August 14, 2009 8:15 PM
Aland,

Sorry, I figured it out. The designer apparently wasn't picking up all the changes I was making. I had to do a Clean build and now everything works as expected.


Thanks,
~Corey
  • Marked As Answer byCoLeichty Friday, August 14, 2009 8:37 PM
  •  
CoLeichty  Friday, August 14, 2009 8:37 PM

You can use google to search for other answers

Custom Search

More Threads

• Custom design-time control dragging.
• panel layout
• Windows Form Designer Fails to Load
• Windows Forms Designer would not accept event handler found in parent class
• What's Wrong? I lost the changing in editing form and any changing had not been saved.
• Control development tricks & traps
• Property-Collection problem
• Suggested Additions to Modifiers
• unload a dll
• Help with ListView in VC++ 2005