Find answers for the most frequently asked questions
What should I do to make my StringCollection property editable during design-time?
Use this custom editor attribute for the property that is of the StringCollection type (this can be used for other Collection types too if you want to allow entry of strings into the collection during design-time).
Editor('System.Windows.Forms.Design.StringCollectionEditor, System.Design', 'System.Drawing.Design.UITypeEditor, System.Drawing'),
public YourCollection YourProp{get{...}set{...}}
StringCollectionEditor is not public so you have to use the above constructor override and specify the typename. This editor should allow you
to edit your collection without any problems.
How can I paint a representation of enum values using a UITypeEditor?
The following HatchStyleEditor class draws a graphical representation for values in the HatchStyle enumeration. HatchStyleEditor is derived from UITypeEditor and overrides the GetPaintValueSupported method and returns true. GetPaintValueSupported indicates that this editor supports the painting of a representation of an object’s value.
PaintValue paints the representative value to the canvas.
How can I let the user edit my Multi-Dimensional collection?
This is usually a problem if you have a custom collection type MyCollection which itself can take items of type MyCollection.
The problem is because a single instance of a UITypeEditor is used by the framework irrespective of how many types and instances it serves to edit. Which means you cannot start editing your MyCollection from within a MyCollection editor, since the editor is already open.
To work around this problem, you can provide a custom editor as follows:
publicclassCustomCollectionEditor : CollectionEditor
{
// The base class has its own version of this property// cached CollectionFormprivate CollectionForm collectionForm;
publicCustomCollectionEditor(Type type)
: base(type)
{
}
publicoverrideobjectEditValue(
ITypeDescriptorContext context, IServiceProvider provider,
objectvalue)
{
if(this.collectionForm != null && this.collectionForm.Visible)
{
// If the CollectionForm is already visible, then create a new instance// of the editor and delegate this call to it.
BarItemsCollectionEditor editor = new BarItemsCollectionEditor(this.CollectionType);
return editor.EditValue(context, provider, value);
}
elsereturnbase.EditValue(context, provider, value);
}
protectedoverride CollectionForm CreateCollectionForm()
{
// Cache the CollectionForm being used.this.collectionForm = base.CreateCollectionForm();
returnthis.collectionForm;
}
}
From within a PropertyGrid, is there any way to display property names that differ from the actual class property names
You can do this but it’s not as simple as using an attribute. If you want to modify the property names for your component, you have to interact with the reflection mechanism that the grid is using by implementing
ICustomTypeDescriptor. The grid operates on objects called PropertyDescriptors with are the Framework’s generic wrapper for a property, where reflection is a specific implementation. So what ICustomTypeDescriptor allows you to do is to have *your object* asked for it’s properties rather than than the default system, which is reflection.
You then write your own derived version of PropertyDescriptor (an abstract class in System.ComponentModel) and return your property descriptors instead of the ones that come back from the TypeDescriptor… so some of the impl
would look something like this.
publicclassMyFriendlyNamePropertyDescriptor : PropertyDescriptor
{
private PropertyDescriptor baseProp;
privatestring friendlyName;
publicMyFriendlyNamePropertyDescriptor(PropertyDescriptor baseProp, Attribute[] filter)
: base(baseProp)
{
this.baseProp = baseProp;
}
publicoverridestring Name
{
get{returnthis.baseProp.Name;}
}
publicoverridestring DisplayName
{
get
{
return GetFriendlyname(baseProp.Name); //replace with code to return a friendly name
}
}
publicoverridebool IsReadOnly
{
get {return baseProp.IsReadOnly;}
}
publicoverrideboolCanResetValue(object component)
{
returnthis.baseProp.CanResetValue(component);
}
publicoverride Type ComponentType
{
get{return baseProp.ComponentType;}
}
publicoverrideobjectGetValue(object component)
{
returnthis.baseProp.GetValue(component);
}
publicoverride Type PropertyType
{
get{returnthis.baseProp.PropertyType;}
}
publicoverridevoidResetValue(object component)
{
baseProp.ResetValue(component);
}
publicoverridevoidSetValue(object component, object Value)
{
this.baseProp.SetValue(component, Value);
}
publicoverrideboolShouldSerializeValue(object component)
{
returnthis.baseProp.ShouldSerializeValue(component);
}
}
publicclassMyClass : ICustomTypeDescriptor
{
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] filter)
{
PropertyDescriptorCollection baseProps = TypeDescriptor.GetProperties(GetType(), filter);
// notice we use the type here so we don’t recurse
PropertyDescriptor[] newProps = new PropertyDescriptor[baseProps.Count];
for (int i = 0; i < baseProps.Count; i++)
{
newProps[i] = new MyFriendlyNamePropertyDescriptor(baseProps[i], filter);
string oldname = ((PropertyDescriptor)baseProps[i]).DisplayName ;
string newname = ((MyFriendlyNamePropertyDescriptor)newProps[i]).DisplayName;
}
// probably wanna cache this... returnnew PropertyDescriptorCollection(newProps);
}
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);
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents(System.Attribute[] attributes)
{
return TypeDescriptor.GetEvents(this, attributes, true);
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
{
return TypeDescriptor.GetEvents(this, true);
}
PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
{
return TypeDescriptor.GetDefaultProperty(this, true);
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
return TypeDescriptor.GetProperties(this, true);
}
object ICustomTypeDescriptor.GetEditor(System.Type editorBaseType)
{
return TypeDescriptor.GetEditor(this, editorBaseType, true);
}
object ICustomTypeDescriptor.GetPropertyOwner(System.ComponentModel.PropertyDescriptor pd)
{
returnthis;
}
// the code for MyClass.... including the properties to show in the propertygrid
}
(originally from sburke_online@microsoft..nospam..com on microsoft.public.dotnet.framework.windowsforms. This code suggested by Rachid El Masoudi in an email to winformsfaq@syncfusion.com)
How can I allow my user to add more than 1 type of object to my collection, during design-time?
The default CollectionEditor will allow your user to add objects of type returned by your collection’s indexer method.
You can make this CollectionEditor allow your user to pick the type of object to add by deriving from CollectionEditor and making the change as shown below. This will introduce a drop-down in the editor’s ‘Add’ button to allow the user to pick the type he wants to add.
publicclassCustomCollectionEditor : System.ComponentModel.Design.CollectionEditor
{
private Type[] types;
publicCustomCollectionEditor(Type type)
: base(type)
{
types = new Type[]{typeof(ItemType1), typeof(ItemType2), typeof(ItemType3),
typeof(ItemType4)};
}
// Return the types that you want to allow the user to add into your collection.protectedoverride Type[] CreateNewItemTypes()
{
return types;
}
}
[Editor(typeof(CustomCollectionEditor), typeof(UITypeEditor))]
publicclassCustomCollection : IList
{
...
}
Share with