【问题标题】:Modifying structure property in a PropertyGrid在 PropertyGrid 中修改结构属性
【发布时间】:2013-03-22 17:33:03
【问题描述】:

为什么SomeClass.ClassField.StructField 属性在propertyGrid 中没有变化? 看来,propertyGridSomeStruct 实例更改后不会调用 SomeClass.ClassField.set。但同样的代码适用于 Point 而不是 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;

【问题讨论】:

  • 结构应该是不可变的
  • 这个是可变的。与点/矩形/等相同。
  • 好点(多余的字符)
  • 请注意“ExpandableObjectConverter”中的“Object”一词。您将编辑结构的盒装副本,它不会传播回来。以PointConverter的实现为例。
  • @Hans Passant,非常感谢,它有效。

标签: .net winforms propertygrid


【解决方案1】:

您需要一个特殊的 TypeConverter 来覆盖 TypeConverter.GetCreateInstanceSupported,否则按值复制/装箱魔术会在属性网格处理所有这些的方式背后发生。

这是一种适用于大多数值类型的方法。你这样声明:

[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;
    }
}

请注意,它不支持纯字段结构,仅支持具有属性的结构,但 ExpandableObjectConverter 也不支持这些,它需要更多代码来完成。

【讨论】:

    【解决方案2】:

    我调整了 Simon Mourier 的答案以避免 ValueTypeTypeConverter 成为泛型的需要:

    public class ValueTypeTypeConverter : System.ComponentModel.ExpandableObjectConverter
    {
        public override bool GetCreateInstanceSupported(System.ComponentModel.ITypeDescriptorContext context)
        {
            return true;
        }
    
        public override object CreateInstance(System.ComponentModel.ITypeDescriptorContext context, System.Collections.IDictionary propertyValues)
        {
            if (propertyValues == null)
                throw new ArgumentNullException("propertyValues");
    
            object boxed = Activator.CreateInstance(context.PropertyDescriptor.PropertyType);
            foreach (System.Collections.DictionaryEntry entry in propertyValues)
            {
                System.Reflection.PropertyInfo pi = context.PropertyDescriptor.PropertyType.GetProperty(entry.Key.ToString());
                if ((pi != null) && (pi.CanWrite))
                {
                    pi.SetValue(boxed, Convert.ChangeType(entry.Value, pi.PropertyType), null);
                }
            }
            return boxed;
        }
    }
    

    【讨论】:

      【解决方案3】:

      在我的例子中,泛型参数在编译时是未知的(插件的选项结构)。您可以使用context.PropertyDescriptor.GetValue(context.Instance); 获取当前值的副本:

        public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
        {
           if (propertyValues == null)
              throw new ArgumentNullException("propertyValues");
      
           object boxed = context.PropertyDescriptor.GetValue(context.Instance);
           foreach (DictionaryEntry entry in propertyValues)
           {
              PropertyInfo pi = boxed.GetType().GetProperty(entry.Key.ToString());
              if (pi != null && pi.CanWrite)
                 pi.SetValue(boxed, Convert.ChangeType(entry.Value, pi.PropertyType), null);
           }
           return boxed;
        }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-15
        • 1970-01-01
        • 2018-10-21
        • 1970-01-01
        • 1970-01-01
        • 2015-09-20
        • 1970-01-01
        相关资源
        最近更新 更多