6

SomeClass.ClassField.StructFieldでプロパティが変更されないのはなぜpropertyGridですか? インスタンスが変更された後にpropertyGrid呼び出されないようです。しかし、同じコードはの代わりにうまく機能します。SomeClass.ClassField.setSomeStructPointSomeStruct

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

3 に答える 3

8

TypeConverter.GetCreateInstanceSupported をオーバーライドする特別な TypeConverter が必要ですそうしないと、プロパティ グリッドがこれらすべてを処理する方法で、値によるコピー/ボックス化の魔法が舞台裏で発生するためです。

これは、ほとんどの値の型で機能するはずです。次のように宣言します。

[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 はこれらもサポートしていないことに注意してください。これを行うには、より多くのコードが必要になります。

于 2013-04-02T07:36:59.533 に答える
3

ValueTypeTypeConverter をジェネリックにする必要がないように、Simon Mourier の回答を微調整しました。

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;
    }
}
于 2014-01-03T02:09:52.410 に答える
0

私の場合、一般的な引数はコンパイル時にわかりません (プラグインのオプション構造)。次を使用して、現在の値のコピーを取得できます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;
  }
于 2015-06-22T12:03:09.047 に答える