2011-09-13 1 views
1

IList 속성이있는 MyClassA 클래스가 있습니다. MyClassA의 모든 속성을 표시하기 위해 PropertyGrid 컨트롤을 사용하고 있으며 MyClassA의 PropertyGrid를 통해 MyClassB 목록을 표시 및 편집 할 수 있습니다.PropertyGrid 편집 가능한 목록을 어떻게 추가합니까 <Class>?

현재 MyClassB 목록의 속성을 제외하고 속성 눈금에 다른 모든 속성이 표시됩니다. 사용자가 목록에서 항목을 추가/편집/제거 할 수있는 속성 표에 MyClassB 목록을 추가하는 방법은 무엇입니까?

나는 아직도 파고 있지만 그래도 이것에 대해 자세하게 설명하는 예제는 실제로 찾을 수 없었습니다.

+0

목록에 목록이있어서 pGrid 용 사용자 정의 편집기로 목록을 표시하고 싶습니까? –

+0

다소 차이가 있습니다. 내 메인에 MyClassA 목록이 있습니다. MyClassA의 해당 목록은 pGrid에 바인딩됩니다. 각 MyClassA에는 MyClassB와 관련된 목록이 있습니다. 모든 MyClassB를 현재 표시되고있는 MyClassA에 대한 목록에 표시하고 사용자가 연결된 MyClassB를 편집하거나 MyClassB에 포함 된 MyClassB 목록에 새 MyClassB를 추가 할 수있게하려고합니다. 말이 돼? –

+0

이러한 유형의 사용자 지정을 위해서는 특정 유형의 속성이 주어지면 사용자 지정 사용자 정의 컨트롤을 사용하여 표시하는 사용자 지정 그리드 용 그리드를 만들어야합니다. 내가 올바르게 이해하고 있다면. –

답변

1

지금까지 내가 해왔 던 해결책이 있습니다. 그러나 내가 찾고있는 것에 여전히 100 % 적합하지는 않습니다.

는 내 취향에 대한 수정이 참조를 발견 http://www.codeproject.com/KB/tabs/customizingcollectiondata.aspx

것은 내가 한 것은 CollectionBase에서 상속하고는은 ICustomTypeDescriptor를 사용하는 새로운 클래스를 생성했다.

이 작업을 수행하고 기본 기능을 구현 한 후에 클래스의 PropertyDescriptor를 만들어야했습니다.

public class ZoneCollection : CollectionBase, ICustomTypeDescriptor 
{ 
    #region Collection Implementation 

    /// <summary> 
    /// Adds an zone object to the collection 
    /// </summary> 
    /// <param name="emp"></param> 
    public void Add(Zone zone) 
    { 
     this.List.Add(zone); 
    } 

    /// <summary> 
    /// Removes an zone object from the collection 
    /// </summary> 
    /// <param name="emp"></param> 
    public void Remove(Zone zone) 
    { 
     this.List.Remove(zone); 
    } 

    /// <summary> 
    /// Returns an zone object at index position. 
    /// </summary> 
    public Zone this[int index] 
    { 
     get 
     { 
      return (Zone)this.List[index]; 
     } 
    } 

    #endregion 

    // Implementation of interface ICustomTypeDescriptor 
    #region ICustomTypeDescriptor impl 

    public String GetClassName() 
    { 
     return TypeDescriptor.GetClassName(this, true); 
    } 

    public AttributeCollection GetAttributes() 
    { 
     return TypeDescriptor.GetAttributes(this, true); 
    } 

    public String GetComponentName() 
    { 
     return TypeDescriptor.GetComponentName(this, true); 
    } 

    public TypeConverter GetConverter() 
    { 
     return TypeDescriptor.GetConverter(this, true); 
    } 

    public EventDescriptor GetDefaultEvent() 
    { 
     return TypeDescriptor.GetDefaultEvent(this, true); 
    } 

    public PropertyDescriptor GetDefaultProperty() 
    { 
     return TypeDescriptor.GetDefaultProperty(this, true); 
    } 

    public object GetEditor(Type editorBaseType) 
    { 
     return TypeDescriptor.GetEditor(this, editorBaseType, true); 
    } 

    public EventDescriptorCollection GetEvents(Attribute[] attributes) 
    { 
     return TypeDescriptor.GetEvents(this, attributes, true); 
    } 

    public EventDescriptorCollection GetEvents() 
    { 
     return TypeDescriptor.GetEvents(this, true); 
    } 

    public object GetPropertyOwner(PropertyDescriptor pd) 
    { 
     return this; 
    } 


    /// <summary> 
    /// Called to get the properties of this type. Returns properties with certain 
    /// attributes. this restriction is not implemented here. 
    /// </summary> 
    /// <param name="attributes"></param> 
    /// <returns></returns> 
    public PropertyDescriptorCollection GetProperties(Attribute[] attributes) 
    { 
     return GetProperties(); 
    } 

    /// <summary> 
    /// Called to get the properties of this type. 
    /// </summary> 
    /// <returns></returns> 
    public PropertyDescriptorCollection GetProperties() 
    { 
     // Create a collection object to hold property descriptors 
     PropertyDescriptorCollection pds = new PropertyDescriptorCollection(null); 

     // Iterate the list of employees 
     for (int i = 0; i < this.List.Count; i++) 
     { 
      // Create a property descriptor for the zone item and add to the property descriptor collection 
      ZoneCollectionPropertyDescriptor pd = new ZoneCollectionPropertyDescriptor(this, i); 
      pds.Add(pd); 
     } 
     // return the property descriptor collection 
     return pds; 
    } 

    #endregion 
} 

/// <summary> 
/// Summary description for CollectionPropertyDescriptor. 
/// </summary> 
public class ZoneCollectionPropertyDescriptor : PropertyDescriptor 
{ 
    private ZoneCollection collection = null; 
    private int index = -1; 

    public ZoneCollectionPropertyDescriptor(ZoneCollection coll, int idx) : 
     base("#" + idx.ToString(), null) 
    { 
     this.collection = coll; 
     this.index = idx; 
    } 

    public override AttributeCollection Attributes 
    { 
     get 
     { 
      return new AttributeCollection(null); 
     } 
    } 

    public override bool CanResetValue(object component) 
    { 
     return true; 
    } 

    public override Type ComponentType 
    { 
     get 
     { 
      return this.collection.GetType(); 
     } 
    } 

    public override string DisplayName 
    { 
     get 
     { 
      Zone zone = this.collection[index]; 
      return zone.ID.ToString(); 
     } 
    } 

    public override string Description 
    { 
     get 
     { 
      Zone zone = this.collection[index]; 
      StringBuilder sb = new StringBuilder(); 
      sb.Append(zone.ID.ToString()); 

      if (zone.Streets.Route != String.Empty || zone.Streets.Crossing != String.Empty) 
       sb.Append("::"); 
      if (zone.Streets.Route != String.Empty) 
       sb.Append(zone.Streets.Route); 
      if (zone.Streets.Crossing != String.Empty) 
      { 
       sb.Append(" and "); 
       sb.Append(zone.Streets.Crossing); 
      } 

      return sb.ToString(); 
     } 
    } 

    public override object GetValue(object component) 
    { 
     return this.collection[index]; 
    } 

    public override bool IsReadOnly 
    { 
     get { return false; } 
    } 

    public override string Name 
    { 
     get { return "#" + index.ToString(); } 
    } 

    public override Type PropertyType 
    { 
     get { return this.collection[index].GetType(); } 
    } 

    public override void ResetValue(object component) 
    { 
    } 

    public override bool ShouldSerializeValue(object component) 
    { 
     return true; 
    } 

    public override void SetValue(object component, object value) 
    { 
     // this.collection[index] = value; 
    } 
} 

사거리 지금 ZoneCollection 대신의 IList의를 포함하고 내가 지금 수정/추가/컬렉션에 포함 된 영역을 제거 할 수 있습니다 : 여기

는 코드입니다.

이제 좀 더 일반화 할 수 있다면 비교적 행복 할 것입니다. 내 모델에 대한 또 다른 방해물은 IList 대신 Collection base로부터 상속 받아야한다는 것입니다. 이것은 NHibernate에 대한 클래스 매핑을 완전히 망가 뜨 렸습니다. 그리고 이제는 위에서 언급 한 방법을 사용하여이 목록을 다시 매핑하는 방법을 찾아야합니다.

누군가 더 자세히 설명하고 싶다면 좀 더 통찰력을 주시면 감사하겠습니다.

0

나는이 주제가 2 년 이상 된 것을 알고 있지만 아마도 이것은 당신에게 흥미로울 수 있습니다.

비슷한 문제가있었습니다. 다음과 함께 시작 : 3D-Space에서 Property-Grid에서 구성 할 수있는 Point가 필요합니다. 이 경우 클래스 Koord가 생성되었습니다. 이것은 Vexel TestBock을 만들려면

(이 :-)를 위해 무엇을 알아 위키 백과 확인) (일부 3D 객체에 사용되는 : PropertyGrid가에서 그것을 변경하려면, 나는 새로운 클래스 "TypeConverter를 KoordConverter"를 생성) 나는 List of Vexels를 사용하고있다. 불행히도 내 프로그램에 TestBlocks 목록이 필요하며 Property-Grid를 통해 볼 수 있습니다.

는 맨 위의 시작하려면 :

public partial class FormMain : Form 
{ 
    private BlockProperties _bp = new BlockProperties(); 

    public FormMain() 
    { 
     InitializeComponent(); 
     pgProperties.SelectedObject = _bp; 
    } 
[...] 
} 

더 클래스 BlockProperties 내가 안에 무엇이 당신을 보여줄 수있는 비트를 작성 TestBocks의 목록이 포함되어 있습니다.

class BlockProperties 
{ 
    public List<TestBocks> Testing { get; set; } 

    public BlockProperties() 
    { 
     Testing = new List<TestBocks>(3); 

     List<Vexel> t1 = new List<Vexel>(1); 
     t1.Add(new Vexel(new Koord(1,0,1), 1)); 

     List<Vexel> t2 = new List<Vexel>(2); 
     t2.Add(new Vexel(new Koord(2, 0, 1), 2)); 
     t2.Add(new Vexel(new Koord(2, 0, 2), 2)); 

     List<Vexel> t3 = new List<Vexel>(3); 
     t3.Add(new Vexel(new Koord(3, 0, 1), 3)); 
     t3.Add(new Vexel(new Koord(3, 0, 2), 3)); 
     t3.Add(new Vexel(new Koord(3, 0, 3), 3)); 

     TestBocks tb1 = new TestBocks(); 
     tb1.Koords = t1; 

     TestBocks tb2 = new TestBocks(); 
     tb2.Koords = t2; 

     TestBocks tb3 = new TestBocks(); 
     tb3.Koords = t3; 

     Testing.Add(tb1); 
     Testing.Add(tb2); 
     Testing.Add(tb3); 
    [...] 
    } 
[...] 
} 

다음

는 Vexels에서 직진

[Serializable] 
public class TestBocks 
{ 
    public List<Vexel> Vexels{ get; set; } 
    public TestBocks() 
    { 
     Vexels = new List<Vexel>(); 
    } 
} 

단순히 내 TestBlock 클래스입니다 내 프로그램에 필요한 마법의 대부분 : 심지어 수 있도록 여기)를 ToString을 (넣어 그것은 디버깅하는 동안 쉽습니다.

public class Vexel 
{ 
    private Koord _origin; 
    private double _extent; 

    public Koord Origin { get { return _origin; } set { _origin = value; } } 

    public double Extent { get { return _extent; } set { _extent = value; } } 

    public string ToString() 
    { 
     NumberFormatInfo nFormatInfo = new NumberFormatInfo 
     { 
      NumberDecimalSeparator = ".", 
      NumberGroupSeparator = "" 
     }; 
     return String.Format(nFormatInfo, "Origin;{0};{1};{2};Extent;{3}", _origin.X, _origin.Y, _origin.Z, _extent); 
    } 

    public Vexel() 
    { 
     _origin = new Koord(0,0,0); 
     Extent = 0; 
    } 

    public Vexel(Koord origin, double extent) 
    { 
     //TODO do some checking 
     _origin = origin; 
     _extent = extent; 
    } 

지금까지 PropertyGrid에서는 모든 것이 잘 작동했지만 코드를 편집 할 수 없었습니다. 클래스는 매우 간단했지만 PropertyGrid에서는 편집 할 수 없었습니다. TypeConverterClass 추가 는 TypeConverter가 쓸 수있는 가장 복잡한 코드이었다

[TypeConverter(typeof(KoordConverter))] 
[Serializable] 
public class Koord 
{ 
    private double p_1; 
    private double p_2; 
    private double p_3; 

    public Koord(double x, double y, double z) 
    { 
     this.p_1 = x; 
     this.p_2 = y; 
     this.p_3 = z; 
    } 

    public string ToString() 
    { 
     return String.Format("X;{0};Y;{1};Z;{2}", p_1, p_2, p_3); 
    } 

    public double X { get { return p_1; } } 
    public double Y { get { return p_2; } } 
    public double Z { get { return p_3; } } 
} 

(당신이 KOORD의 코드를 아래의 TypeConverter를 찾을 수 있습니다)이 문제를 해결했다. 아래 찾을 수 있습니다 :이 모든이 설정된 후

public class KoordConverter : TypeConverter 
{ 
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 
    { 
     return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); 
    } 

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
    { 
     return destinationType == typeof(InstanceDescriptor) || base.CanConvertTo(context, destinationType); 
    } 

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) 
    { 
     string text = value as string; 
     if (text == null) 
     { 
      return base.ConvertFrom(context, culture, value); 
     } 
     string text2 = text.Trim(); 
     if (text2.Length == 0) 
     { 
      return null; 
     } 
     if (culture == null) 
     { 
      culture = CultureInfo.CurrentCulture; 
     } 
     char c = culture.TextInfo.ListSeparator[0]; 
     string[] array = text2.Split(new char[] 
     { 
      c 
     }); 
     int[] array2 = new int[array.Length]; 
     TypeConverter converter = TypeDescriptor.GetConverter(typeof(int)); 
     for (int i = 0; i < array2.Length; i++) 
     { 
      array2[i] = (int)converter.ConvertFromString(context, culture, array[i]); 
     } 
     if (array2.Length == 3) 
     { 
      return new Koord(array2[0], array2[1], array2[2]); 
     } 
     throw new ArgumentException("TextParseFailedFormat"); 
    } 

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) 
    { 
     if (destinationType == null) 
     { 
      throw new ArgumentNullException("destinationType"); 
     } 
     if (value is Koord) 
     { 
      if (destinationType == typeof(string)) 
      { 
       Koord Koord = (Koord)value; 
       if (culture == null) 
       { 
        culture = CultureInfo.CurrentCulture; 
       } 
       string separator = culture.TextInfo.ListSeparator + " "; 
       TypeConverter converter = TypeDescriptor.GetConverter(typeof(int)); 
       string[] array = new string[3]; 
       int num = 0; 
       array[num++] = converter.ConvertToString(context, culture, Koord.X); 
       array[num++] = converter.ConvertToString(context, culture, Koord.Y); 
       array[num++] = converter.ConvertToString(context, culture, Koord.Z); 
       return string.Join(separator, array); 
      } 
      if (destinationType == typeof(InstanceDescriptor)) 
      { 
       Koord Koord2 = (Koord)value; 
       ConstructorInfo constructor = typeof(Koord).GetConstructor(new Type[] 
       { 
        typeof(double), 
        typeof(double), 
        typeof(double) 
       }); 
       if (constructor != null) 
       { 
        return new InstanceDescriptor(constructor, new object[] 
        { 
         Koord2.X, 
         Koord2.Y, 
         Koord2.Z 
        }); 
       } 
      } 
     } 
     return base.ConvertTo(context, culture, value, destinationType); 
    } 

    public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues) 
    { 
     if (propertyValues == null) 
     { 
      throw new ArgumentNullException("propertyValues"); 
     } 
     object obj = propertyValues["X"]; 
     object obj2 = propertyValues["Y"]; 
     object obj3 = propertyValues["Z"]; 
     if (obj == null || obj2 == null || obj3 == null || !(obj is double) || !(obj2 is double) || !(obj3 is double)) 
     { 
      throw new ArgumentException("PropertyValueInvalidEntry"); 
     } 
     return new Koord((double)obj, (double)obj2, (double)obj3); 
    } 

    public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) 
    { 
     return true; 
    } 

    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) 
    { 
     PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(Koord), attributes); 
     return properties.Sort(new string[] 
     { 
      "X", 
      "Y", 
      "Z" 
     }); 
    } 

    public override bool GetPropertiesSupported(ITypeDescriptorContext context) 
    { 
     return true; 
    } 
} 

는 기본적으로, 그들이 스텝 오버하면 누군가 도움 객체 (TestBlocks 각 TestBlock 내 Vexels) 는 희망의 목록을 수정 할 ploblem 없었다 이 스레드.

안부

로빈 혈액

PS : 편집은, 어쩌면 당신은 당신의 생성자 오른쪽 PropertyGrid가 아무런 문제를 얻을하지 않았다입니다!? http://i.stack.imgur.com/LD3zf.png

관련 문제