为什么 SomeClass.ClassField.StructField
属性不会在的PropertyGrid
改变?
看来,的PropertyGrid
不叫 SomeClass.ClassField.set
在 SomeStruct
的实例已被更改。但是,同样的code可以很好地点
而不是 SomeStruct
。
[类型转换器(typeof运算(ExpandableObjectConverter))]
公共结构SomeStruct
{
私人诠释structField;
公众诠释StructField
{
得到
{
返回structField;
}
组
{
structField =价值;
}
}
公共重写字符串的ToString()
{
返回StructField:+ StructField;
}
}
[类型转换器(typeof运算(ExpandableObjectConverter))]
公共密封类SomeClass的
{
公共SomeStruct ClassField
{
得到;
组;
}
}
...
VAR SomeClass的=新SomeClass的
{
ClassField =新SomeStruct
{
StructField = 42
}
};
propertyGrid.SelectedObject = SomeClass的;
解决方案
您需要一个特殊的类型转换器,它覆盖的 TypeConverter.GetCreateInstanceSupported ,因为以其他方式复制按值/拳击魔术发生在幕后的属性网格处理这一切的方式。
下面是一个应该适用于大多数值类型。您声明它是这样的:
[类型转换器(typeof运算(ValueTypeTypeConverter< SomeStruct>))]
公共结构SomeStruct
{
公众诠释StructField {获得;组; }
}
公共类ValueTypeTypeConverter< T> :ExpandableObjectConverter其中T:结构
{
公众覆盖布尔GetCreateInstanceSupported(ITypeDescriptorContext上下文)
{
返回true;
}
公众覆盖对象的CreateInstance(ITypeDescriptorContext背景下,IDictionary的propertyValues)
{
如果(propertyValues == NULL)
抛出新ArgumentNullException(propertyValues);
牛逼RET =默认(T);
反对盒装= RET;
的foreach(在propertyValues的DictionaryEntry项)
{
。的PropertyInfo PI = ret.GetType()的getProperty(entry.Key.ToString());
如果(PI = NULL和放大器;!&安培; pi.CanWrite)
{
pi.SetValue(盒装,Convert.ChangeType(entry.Value,pi.PropertyType),NULL);
}
}
返程(T)盒装;
}
}
请注意它不支持纯粹的现场只结构,只有一个与属性,但ExpandableObjectConverter不支持这些或者说,它需要更多的code做到这一点。
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;
解决方案
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.