2011-09-13 36 views
1

我有一個具有IList屬性的類MyClassA。我正在使用PropertyGrid控件來顯示MyClassA的所有屬性,我希望通過MyGlassA的PropertyGrid顯示和編輯MyClassB的列表。PropertyGrid如何添加可編輯列表<Class>?

我現在已經顯示在屬性網格中所有其他屬性除了是MyClassB的列表中的屬性。我如何着手將MyClassB列表添加到用戶可以添加/編輯/從列表中刪除項目的屬性網格中?

我還沒有真正能夠找到細講這個作爲然而,儘管我仍然在挖什麼例子。

+0

因此,你有一個列表中的列表,你想顯示該列表與某種自定義編輯器爲您的pGrid? –

+0

或多或少。我的Main中有一個MyClassA的列表。 MyClassA的列表綁定到pGrid。每個MyClassA都有一個與它關聯的MyClassB的列表。我想在當前正在顯示的MyClassA的列表中顯示所有MyClassB,並允許用戶編輯與其關聯的每個MyClassB,或者將新的MyClassB添加到包含在MyClassA中的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,現在我可以編輯/添加/刪除包含在集合內的區域。

現在,如果我能使這個更通用,我會相對高興。我的模型的另一個障礙是我必須使用這個來繼承Collection集合,而不是IList。這完全破壞了我的NHibernate類的映射,現在我不得不嘗試使用上面提到的方法重新映射這個列表。

如果有人想進一步闡述這一點,我會非常感謝一些更深入的瞭解。

0

我知道這個題目是超過2歲,但也許這可能是對你有意思。

我有一個類似的問題。 開始於:我需要3D空間中的一個點,它應該可以在Property-Grid中配置 爲此,我創建了一個Class Koord。爲了使在PropertyGrid中多變的,我創建了一個新的類別「KoordConverter:TypeConverter的」這是在Vexel(檢查維基百科,找出它是:-))

要創建一個TestBock(一些三維對象使用 )我正在使用一個Vexels列表。 不幸的是,我需要一個TestBlocks列表,在我的程序中,通過Property-Grid可見。

要朵蒙特開始:

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

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

的Class 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); 
    [...] 
    } 
[...] 
} 

接下來是我的TestBlock類,這簡直是直線前進

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

在Vexels是最神奇的,我需要爲我的計劃: 我甚至把一個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一切正常,但我無法編輯Koords。 該類非常簡單,但在PropertyGrid中不可編輯。 添加TypeConverterClass解決了這個問題(你可以找到Koord的代碼下面的類型轉換器)

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

的類型轉換器是最複雜的代碼編寫。您可以在下面找到它:

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

基本上所有的這個成立後,它並沒有ploblem修改對象(TestBlocks或每個TestBlock內Vexels) 希望的任何目錄也可以幫助別人,如果他們跨過此主題。

問候

羅賓血

PS:編輯是PropertyGrid中沒有問題,也許你只是沒有得到你的構造吧!? http://i.stack.imgur.com/LD3zf.png

相關問題