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 |
|