I have many custom classes that I am using that I will explain and post examples of. After Explaining what they all do I will try to clearly describe the conditions under wh
Having worked with TypeConverters myself, I can confirm they are a major pain in the bottom parts. You get nada info about what is actually going wrong, only weird output...
Idk if it helps, but maybe it is a problem that you add an empty (null) array to anything that is not an IEnumerable? Try moving the add instruction into the scope of the if (...). I dont think there is any harm in that.
Also, are you certain that (in the last example with the EndJoint) the getter does not return a null pointer? Blank entries smell like null pointers being passed from my experiences.
You don't have to create special classes to use the property grid. Just decorate the properties with the proper attributes. Here is an example:
Two custom classes:
public class MyObjType1
{
public int Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
public class MyObjType2
{
public string Reference { get; set; }
public override string ToString()
{
return Reference;
}
}
Note the ToString
is overriden, that's what the property grid uses by default if no TypeConverter is defined for a given type.
One "holder" class that has a collection of custom objects:
public class MyHolder
{
public MyHolder()
{
Objects = new List<object>();
}
public string Name { get; set; }
[TypeConverter(typeof(MyCollectionConverter))]
public List<object> Objects { get; private set; }
}
Note the custom TypeConverter
applied directly to the Objects
property. Here is the source:
public class MyCollectionConverter : ExpandableObjectConverter
{
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
{
IEnumerable enumerable = value as IEnumerable;
if (enumerable == null)
return base.GetProperties(context, value, attributes);
int i = 0;
List<PropertyDescriptor> list = new List<PropertyDescriptor>();
foreach (object obj in enumerable)
{
MyItemPropertyDescriptor index = new MyItemPropertyDescriptor(i.ToString(), obj);
list.Add(index);
i++;
}
return new PropertyDescriptorCollection(list.ToArray());
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType != typeof(string))
return base.ConvertTo(context, culture, value, destinationType);
IEnumerable enumerable = value as IEnumerable;
if (enumerable == null)
return base.ConvertTo(context, culture, value, destinationType);
StringBuilder sb = new StringBuilder();
foreach (object obj in enumerable)
{
if (sb.Length > 0)
{
sb.Append(',');
}
sb.AppendFormat("{0}", obj);
}
return sb.ToString();
}
}
Note we override ConvertTo
and give it a special string that displays a comma-separated list of objects in the list. The GetProperties
is also overriden and uses a special PropertyDescriptor
; It adds an ExpandableObjectConverter
attribute to sub objects so they can be expanded too:
public class MyItemPropertyDescriptor : PropertyDescriptor
{
private object _value;
public MyItemPropertyDescriptor(string name, object value)
: base(name, new[] { new TypeConverterAttribute(typeof(ExpandableObjectConverter)) })
{
_value = value;
}
public override bool IsReadOnly
{
get { return false; }
}
public override object GetValue(object component)
{
return _value;
}
public override Type PropertyType
{
get { return _value == null ? typeof(object) : _value.GetType(); }
}
public override bool ShouldSerializeValue(object component)
{
return false;
}
public override Type ComponentType
{
get { return typeof(object); }
}
public override bool CanResetValue(object component)
{
return false;
}
public override void ResetValue(object component)
{
}
public override void SetValue(object component, object value)
{
}
}
Now, here is some sample code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
MyHolder holder = new MyHolder();
for (int i = 0; i < 3; i++)
{
holder.Objects.Add(new MyObjType1 { Id = i, Name = i + "Name" });
}
for (int i = 0; i < 3; i++)
{
holder.Objects.Add(new MyObjType2 { Reference = "Ref" + i });
}
propertyGrid1.SelectedObject = holder;
}
}
And the result: