G
Guest
I've been using a PropertyGrid to display an object containing a property
that is a Custom Collection. I created a UITypeEditor for this Custom
Collection and associated it with the property via the EditorAttribute:
<code>
public class ObjectContainingCustomCollectionAsProperty
{
private CustomCollection m_CustomCollection;
[Editor(typeof(CustomCollectionEditor),typeof
(System.Drawing.Design.UITypeEditor))]
DescriptionAttribute("Custom Collection"),
TypeConverter(typeof(CustomCollectionConverter))]
public CustomCollection CustomColl
{
get
{
return m_CustomCollection;
}
set
{
m_CustomCollection = value;
}
}
}
internal class CustomCollectionConverter : TypeConverter {
public override object ConvertTo(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture, object value, Type destType)
{
if (destType == typeof(string) && value is CustomCollection)
{
return "Custom Collection";
}
return base.ConvertTo(context, culture, value, destType);
}
}
public class CustomCollectionEditor : UITypeEditor
{
public override UITypeEditorEditStyle GetEditStyle(
ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.DropDown;
}
public override object
EditValue(System.ComponentModel.ITypeDescriptorContext context,
IServiceProvider provider, object value)
{
IWindowsFormsEditorService wfes = provider.GetService(
typeof(IWindowsFormsEditorService)) as
IWindowsFormsEditorService;
if (wfes != null)
{
ObjectContainingCustomCollectionAsProperty obj =
(ObjectContainingCustomCollectionAsProperty)context.Instance;
CustomCollection c = obj.CustomColl;
CheckedListBox lb = new CheckedListBox();
for(int i=0;i<CustomCollection.Count();i++)
{
lb.Items.Add(c.GetName(i));
if (c)
{
lb.SetItemChecked(i, true);
}
}
wfes.DropDownControl(lb);
for(int i=0;i<lb.Items.Count;i++)
{
if (lb.GetItemCheckState(i) == CheckState.Checked)
{
c = true;
}
else
{
c = false;
}
}
//Note: you must clone the collection
//or PropertyGrid's GridItem doesn't
//commit the change -- (since it
//and doesn't commit a change
//if new value == old value
//which it will if the value is
//reference type)
value = c.Clone();
}
return value;
}
}
</code>
I had problems with the above code UNTIL I used Lutz Roeder's awesome tool
--.NET Reflector tool -- free off the internet at
http://www.aisto.com/roeder/dotnet/
and looked at the PropertyGrid source code -- there's a method in class
GridEntry
used by the PropertyGridView inside of PropertyGrid called
EditPropertyValue. This method does the following check:
<code>
internal virtual void EditPropertyValue(PropertyGridView iva)
{
....
object obj1 = this.PropertyValue;
object obj2 = this.UITypeEditor.EditValue(this,this,obj1);
if(this.Disposed)
{
return;
}
if((obj1 != obj1) && this.IsValueEditable)
{
iva.CommitValue(this,obj2);
}
....}//end of method EditPropertyValue(PropertyGridView iva)
</code>
So the punchline to this whole story is IF YOU'RE USING A PROPERTY IN THE
PROPERTY GRID THAT IS A REFERENCE TYPE THEN BE SURE TO RETURN A CLONE OF THAT
REFERENCE TYPE FROM YOUR UITYPEEDITOR CLASS'S EDITVALUE METHOD!!!!!
Thanks for letting me share this -- I was very happy to finally discover this.
Now if only Microsoft allowed you to debug into their framework such
problems would be even easier to resolve! ; )
that is a Custom Collection. I created a UITypeEditor for this Custom
Collection and associated it with the property via the EditorAttribute:
<code>
public class ObjectContainingCustomCollectionAsProperty
{
private CustomCollection m_CustomCollection;
[Editor(typeof(CustomCollectionEditor),typeof
(System.Drawing.Design.UITypeEditor))]
DescriptionAttribute("Custom Collection"),
TypeConverter(typeof(CustomCollectionConverter))]
public CustomCollection CustomColl
{
get
{
return m_CustomCollection;
}
set
{
m_CustomCollection = value;
}
}
}
internal class CustomCollectionConverter : TypeConverter {
public override object ConvertTo(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture, object value, Type destType)
{
if (destType == typeof(string) && value is CustomCollection)
{
return "Custom Collection";
}
return base.ConvertTo(context, culture, value, destType);
}
}
public class CustomCollectionEditor : UITypeEditor
{
public override UITypeEditorEditStyle GetEditStyle(
ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.DropDown;
}
public override object
EditValue(System.ComponentModel.ITypeDescriptorContext context,
IServiceProvider provider, object value)
{
IWindowsFormsEditorService wfes = provider.GetService(
typeof(IWindowsFormsEditorService)) as
IWindowsFormsEditorService;
if (wfes != null)
{
ObjectContainingCustomCollectionAsProperty obj =
(ObjectContainingCustomCollectionAsProperty)context.Instance;
CustomCollection c = obj.CustomColl;
CheckedListBox lb = new CheckedListBox();
for(int i=0;i<CustomCollection.Count();i++)
{
lb.Items.Add(c.GetName(i));
if (c)
{
lb.SetItemChecked(i, true);
}
}
wfes.DropDownControl(lb);
for(int i=0;i<lb.Items.Count;i++)
{
if (lb.GetItemCheckState(i) == CheckState.Checked)
{
c = true;
}
else
{
c = false;
}
}
//Note: you must clone the collection
//or PropertyGrid's GridItem doesn't
//commit the change -- (since it
//and doesn't commit a change
//if new value == old value
//which it will if the value is
//reference type)
value = c.Clone();
}
return value;
}
}
</code>
I had problems with the above code UNTIL I used Lutz Roeder's awesome tool
--.NET Reflector tool -- free off the internet at
http://www.aisto.com/roeder/dotnet/
and looked at the PropertyGrid source code -- there's a method in class
GridEntry
used by the PropertyGridView inside of PropertyGrid called
EditPropertyValue. This method does the following check:
<code>
internal virtual void EditPropertyValue(PropertyGridView iva)
{
....
object obj1 = this.PropertyValue;
object obj2 = this.UITypeEditor.EditValue(this,this,obj1);
if(this.Disposed)
{
return;
}
if((obj1 != obj1) && this.IsValueEditable)
{
iva.CommitValue(this,obj2);
}
....}//end of method EditPropertyValue(PropertyGridView iva)
</code>
So the punchline to this whole story is IF YOU'RE USING A PROPERTY IN THE
PROPERTY GRID THAT IS A REFERENCE TYPE THEN BE SURE TO RETURN A CLONE OF THAT
REFERENCE TYPE FROM YOUR UITYPEEDITOR CLASS'S EDITVALUE METHOD!!!!!
Thanks for letting me share this -- I was very happy to finally discover this.
Now if only Microsoft allowed you to debug into their framework such
problems would be even easier to resolve! ; )