2013-04-01 30 views
6

Tại sao SomeClass.ClassField.StructField thuộc tính không thay đổi trong một propertyGrid? Có vẻ như, propertyGrid không gọi SomeClass.ClassField.set sau khi phiên bản SomeStruct đã được thay đổi. Nhưng cùng một mã hoạt động tốt với Point thay vì SomeStruct.Sửa đổi thuộc tính cấu trúc trong 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

cấu trúc được coi là bất biến – Filip

+0

Cái này là có thể thay đổi. Tương tự như Point/Rectangle/etc. – nitrocaster

+0

điểm tốt (ký tự thừa) – Filip

Trả lời

7

Bạn cần một TypeConverter đặc biệt đó sẽ ghi đè TypeConverter.GetCreateInstanceSupported bởi vì nếu không copy-by-value/đấm bốc kỳ diệu sẽ xảy ra đằng sau những cảnh trong cách các mạng lưới tài sản xử lý tất cả điều này.

Đây là cách phù hợp với hầu hết các loại giá trị. Bạn khai báo nó như thế này:

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

Lưu ý nó không hỗ trợ tinh khiết lĩnh vực-chỉ cấu trúc, chỉ một với tài sản, nhưng ExpandableObjectConverter không hỗ trợ những một trong hai, nó sẽ đòi hỏi nhiều mã để làm điều đó.

3

tôi tinh chỉnh câu trả lời Simon Mourier để tránh sự cần thiết của ValueTypeTypeConverter là một generic:

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

Trong trường hợp của tôi, lập luận chung chung là không biết đến tại thời gian biên dịch (tùy chọn cấu trúc cho một plugin). Bạn có thể nhận được một bản sao của giá trị hiện tại sử dụng 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; 
    } 
Các vấn đề liên quan