在PropertyGrid中修改结构属性属性、结构、PropertyGrid

2023-09-04 00:54:22 作者:凯伦

为什么 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 ,因为以其他方式复制按值/拳击魔术发生在幕后的属性网格处理这一切的方式。

c 嵌套属性在属性控件propertyGrid中的应用

下面是一个应该适用于大多数值类型。您声明它是这样的:

  [类型转换器(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.