2013-04-01 22 views
6

Dlaczego właściwość nie zmienia się w ? Wygląda na to, że propertyGrid nie wywołuje SomeClass.ClassField.set po zmianie instancji SomeStruct. Ale ten sam kod działa dobrze z Point zamiast z SomeStruct.Modyfikowanie właściwości struktury w PropertyGrid

[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; 
+0

kodowanym mają być niezmienne – Filip

+0

Ten jest zmienny. To samo co Point/Rectangle/etc. – nitrocaster

+0

dobry punkt (dodatkowe znaki) – Filip

Odpowiedz

7

potrzebny jest specjalny TypeConverter który zastępuje TypeConverter.GetCreateInstanceSupported bo inaczej skopiować przez wartość/boks magia dzieje się za sceną w sposób siatka właściwość obsługuje to wszystko.

Oto jeden, który powinien działać dla większości typów wartości. Zadeklarować tak:

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

Uwaga nie obsługuje czystych pola tylko konstrukcjom tylko jedną z właściwości, ale ExpandableObjectConverter nie obsługuje te albo, że to wymaga więcej kodu, aby to zrobić.

3

I manipulowane odpowiedź Simon Mourier, aby uniknąć konieczności ValueTypeTypeConverter być ogólna:

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

W moim przypadku, ogólny argument nie jest znany w czasie kompilacji (struktura opcje dla plugin). Możesz otrzymać kopię aktualnej wartości używając 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; 
    } 
Powiązane problemy