2009-12-10 29 views
5

Tôi đang viết một ứng dụng GUI, nơi tôi cần bật tính năng chỉnh sửa các đối tượng tùy ý (các kiểu của chúng chỉ được biết trong thời gian chạy).PropertyGrid và Dynamic Types of Objects

Tôi đã quyết định sử dụng điều khiển PropertyGrid để bật chức năng này. tôi tạo ra các lớp sau:

[TypeConverter(typeof(ExpandableObjectConverter))] 
[DefaultPropertyAttribute("Value")] 
public class Wrapper 
{ 
    public Wrapper(object val) 
    { 
     m_Value = val; 
    } 

    private object m_Value; 

    [NotifyParentPropertyAttribute(true)] 
    [TypeConverter(typeof(ExpandableObjectConverter))] 
    public object Value 
    { 
     get { return m_Value; } 
     set { m_Value = value; } 
    } 
} 

Khi tôi nhận được một thể hiện của một đối tượng tôi cần phải chỉnh sửa, tôi tạo ra một Wrapper cho nó và đặt nó như là đối tượng được chọn:

Wrapper wrap = new Wrapper(obj); 
propertyGrid.SelectedObject = wrap; 

Nhưng tôi đã chạy vào các vấn đề sau đây - các công trình trên như mong đợi chỉ khi loại obj là một số loại tùy chỉnh (tức là một lớp mà tôi xác định bởi bản thân mình, hoặc được xây dựng trong loại phức tạp) nhưng không phải khi obj là một nguyên thủy.

Ví dụ, nếu tôi xác định:

[TypeConverter(typeof(ExpandableObjectConverter))] 
public class SomeClass 
{ 
    public SomeClass() 
    { 
     a = 1; 
     b = 2; 
    } 

    public SomeClass(int a, int b) 
    { 
     this.a = a; 
     this.b = b; 
    } 

    private int a; 

    [NotifyParentPropertyAttribute(true)] 
    public int A 
    { 
     get { return a; } 
     set { a = value; } 
    } 

    private int b; 

    [NotifyParentPropertyAttribute(true)] 
    public int B 
    { 
     get { return b; } 
     set { b = value; } 
    } 
} 

Và làm:

Sau đó, mọi thứ suôn sẻ sưng. Mặt khác, khi tôi thực hiện như sau:

int num = 1; 
Wrapper wrap = new Wrapper(num); 
propertyGrid.SelectedObject = wrap; 

Sau đó, tôi có thể nhìn thấy giá trị "1" trong lưới (và nó không grayscaled) nhưng tôi không thể chỉnh sửa giá trị. Tôi nhận thấy rằng nếu tôi thay đổi kiểu thuộc tính "Giá trị" của Wrapper thành int và loại bỏ thuộc tính TypeConverter, nó hoạt động. Tôi nhận được hành vi tương tự cho các loại và chuỗi nguyên thủy khác.

Sự cố là gì?

Cảm ơn trước!

Trả lời

5

Nếu bạn đặt ExpandableObjectConverter thành thuộc tính Giá trị, nó sẽ không thể chỉnh sửa được và điều này là bình thường vì CanConvertFrom sẽ trả về false. Nếu bạn loại bỏ bộ chuyển đổi loại, PropertyGrid sẽ sử dụng TypeConverter chung và bạn lại trong cùng một trường hợp. Vì vậy, giải pháp thay thế là đính kèm một TypeConverter thông minh hơn sẽ đóng vai trò như một trình bao bọc cho TypeConverter đúng. Dưới đây là một bẩn (tôi đã không có nhiều thời gian, bạn sẽ hoàn thành nó khi cần thiết kể từ khi tôi chỉ thực hiện phần ConvertFrom):

public class MySmartExpandableObjectConverter : ExpandableObjectConverter 
{ 
    TypeConverter actualConverter = null; 

    private void InitConverter(ITypeDescriptorContext context) 
    { 
     if (actualConverter == null) 
     { 
      TypeConverter parentConverter = TypeDescriptor.GetConverter(context.Instance); 
      PropertyDescriptorCollection coll = parentConverter.GetProperties(context.Instance); 
      PropertyDescriptor pd = coll[context.PropertyDescriptor.Name]; 

      if (pd.PropertyType == typeof(object)) 
       actualConverter = TypeDescriptor.GetConverter(pd.GetValue(context.Instance)); 
      else 
       actualConverter = this; 
     } 
    } 

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 
    { 
     InitConverter(context); 

     return actualConverter.CanConvertFrom(context, sourceType); 
    } 

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) 
    { 
     InitConverter(context); // I guess it is not needed here 

     return actualConverter.ConvertFrom(context, culture, value); 
    } 
} 

Hãy cho tôi biết nếu bạn cần phải tinh chỉnh một cái gì đó.

Nicolas

+0

Cảm ơn rất nhiều, điều đó đã làm được điều đó! :) – Marina

+0

Tại sao dòng này 'parentConverter.GetProperties (context.Instance);' return null? –

0

Xóa "TypeConverter" khỏi thuộc tính "Giá trị", thuộc tính sẽ đọc "TypConverter" từ typeo của giá trị trong thuộc tính.

+1

Tôi đã thử nó, khi tôi làm điều này các mạng lưới tài sản sẽ hiển thị giá trị của bất động sản một cách chính xác, nhưng màu xám quy mô và chỉnh sửa bị vô hiệu hóa (nó thực hiện điều này ngay cả khi obj không phải là một nguyên thủy) – Marina

+0

Thật không may, MS PropertyGrid không phải là hwne thông minh mà bạn không đặt bộ chuyển đổi thành thuộc tính Giá trị của bạn. Đối với int của bạn, nó sẽ không trả về Int32Converter nhưng TypeConverter. Tôi biết điều đó bởi vì tôi phải xử lý trường hợp này trong SPG. Câu trả lời của tôi cho một workaround. –

+0

Hmm, bạn nói đúng. Cho đến bây giờ tôi đã sống trong niềm tin, lưới điện đó rất thông minh. Cảm ơn – TcKs