Modifying structure property in a PropertyGrid
.net, propertygrid, winforms
Solution
You need a special TypeConverter that overrides TypeConverter.GetCreateInstanceSupported because otherwise copy-by-value/boxing magic happens behind the scene in the way the property grid handles all this.
Here is one that should work for most value types. You declare it like this:
[TypeConverter(typeof(ValueTypeTypeConverter<SomeStruct>))]
public struct SomeStruct
{
public int StructField { get; set; }
}
public class ValueTypeTypeConverter<T> : ExpandableObjectConverter where T : struct
{
public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
{
return true;
}
public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
{
if (propertyValues == null)
throw new ArgumentNullException("propertyValues");
T ret = default(T);
object boxed = ret;
foreach (DictionaryEntry entry in propertyValues)
{
PropertyInfo pi = ret.GetType().GetProperty(entry.Key.ToString());
if (pi != null && pi.CanWrite)
{
pi.SetValue(boxed, Convert.ChangeType(entry.Value, pi.PropertyType), null);
}
}
return (T)boxed;
}
}
Note it doesn't support pure field-only structs, only the one with properties, but the ExpandableObjectConverter doesn't support these either, it would require more code to do it.
Problem
Why `SomeClass.ClassField.StructField` property doesn't change in a `propertyGrid`? It seems, `propertyGrid` doesn't call `SomeClass.ClassField.set` after `SomeStruct` instance has been changed. But same code works well with `Point` instead of `SomeStruct`. ``` [TypeConverter(typeof(ExpandableObjectConverter))] public struct SomeStruct { private int structField; public int StructField { get { return structField; } set { structField = value; } } public override string ToString() { return "StructField: " + StructField; } } [TypeConverter(typeof(ExpandableObjectConverter))] public sealed class SomeClass { public SomeStruct ClassField { get; set; } } ... var someClass = new SomeClass { ClassField = new SomeStruct { StructField = 42 } }; propertyGrid.SelectedObject = someClass; ```