0

讓我提供一些關於我如何達到這一點的歷史記錄。PropertyGrid - 來自IList的屬性<T>,如何添加到PropertyGrid以便用戶可以添加/編輯/刪除項目

我最初在我的類中有一個屬性,它是從CollectionsBase派生而來的,並將這個集合映射到PropertyGrid,用戶可以隨意從列表中添加/編輯/刪除項目。

但是,我無法將CollectionsBase與NHibernate進行映射,因此我必須取消初始實現,而不是從CollectionsBase派生,我從IList派生類。

現在我可以映射到NHibernate,但我無法通過PropertyGrid編輯集合。

我需要一些幫助讓2玩對方好。

在我的主類我有一個屬性定義爲:

public virtual ZoneCollection Zones 
    { 
     get { return zones; } 
     set { zones = value; } 
    } 

我區收藏繼承IList的定義如下:

public class ZoneCollection : IList<Zone>, ICustomTypeDescriptor 
{ 
    private IList<Zone> _list; 

    public IList<Zone> _List 
    { 
     get { return _list; } 
    } 

    public ZoneCollection() 
    { 
     _list = new List<Zone>(); 
    } 

    #region Implementation of IEnumerable 

    public IEnumerator<Zone> GetEnumerator() 
    { 
     return _list.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 

    #endregion 

    #region Implementation of ICollection<Zone> 

    public void Add(Zone item) 
    { 
     _list.Add(item); 
    } 

    public void Clear() 
    { 
     _list.Clear(); 
    } 

    public bool Contains(Zone item) 
    { 
     return _list.Contains(item); 
    } 

    public void CopyTo(Zone[] array, int arrayIndex) 
    { 
     _list.CopyTo(array, arrayIndex); 
    } 

    public bool Remove(Zone item) 
    { 
     return _list.Remove(item); 
    } 

    public int Count 
    { 
     get { return _list.Count; } 
    } 

    public bool IsReadOnly 
    { 
     get { return false; } 
    } 

    #endregion 

    #region Implementation of IList<Zone> 

    public int IndexOf(Zone item) 
    { 
     return _list.IndexOf(item); 
    } 

    public void Insert(int index, Zone item) 
    { 
     _list.Insert(index, item); 
    } 

    public void RemoveAt(int index) 
    { 
     _list.RemoveAt(index); 
    } 

    public Zone this[int index] 
    { 
     get { return (Zone)_list[index]; } 
     set { _list[index] = value; } 
    } 

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

}

現在,我的ICustomTypeDescriptor和當這個類派生自CollectionsBase時PropertyDescriptor工作正常,但現在它只是在屬性名稱中顯示類名稱ZoneCollection而沒有「...」按鈕dd /編輯/刪除列表中的項目。

我現在做錯了什麼,它是從IList繼承,這是行不通的?

如果我添加:

[TypeConverter(typeof(ExpandableObjectConverter))] 

到ZoneCollection的開始,我得到了在可擴展樹列出的清單中的項目,但是這不是我所期待的。 「...」按鈕在哪裏打開了一個彈出窗口,使我能夠在從IList而不是CollectionBase繼承時添加/編輯/刪除集合中的項目?

回答

3

PropertyGrid是一個古老的脾氣暴躁的野獸。它需要非通用的IList顯式實現,而不是通用的。

作爲一個站點說明,您可以直接從List<Zone>派生ZoneCollection,並且不需要任何ICustomTypeDescriptor/PropertyDescriptor就這個PropertyGrid問題。

這裏,似乎工作的落實:

public class ZoneCollection : IList<Zone>, IList 
{ 
    private List<Zone> _list = new List<Zone>(); 

    public ZoneCollection() 
    { 
    } 

    public int IndexOf(Zone item) 
    { 
     return _list.IndexOf(item); 
    } 

    public void Insert(int index, Zone item) 
    { 
     _list.Insert(index, item); 
    } 

    public void RemoveAt(int index) 
    { 
     _list.RemoveAt(index); 
    } 

    public Zone this[int index] 
    { 
     get 
     { 
      return _list[index]; 
     } 
     set 
     { 
      _list[index] = value; 
     } 
    } 

    public void Add(Zone item) 
    { 
     _list.Add(item); 
    } 

    public void Clear() 
    { 
     _list.Clear(); 
    } 

    public bool Contains(Zone item) 
    { 
     return _list.Contains(item); 
    } 

    public void CopyTo(Zone[] array, int arrayIndex) 
    { 
     _list.CopyTo(array, arrayIndex); 
    } 

    public int Count 
    { 
     get { return _list.Count; } 
    } 

    public bool IsReadOnly 
    { 
     get { return ((IList)_list).IsReadOnly; } 
    } 

    public bool Remove(Zone item) 
    { 
     return _list.Remove(item); 
    } 

    public IEnumerator<Zone> GetEnumerator() 
    { 
     return _list.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 

    int IList.Add(object value) 
    { 
     int index = Count; 
     Add((Zone)value); 
     return index; 
    } 

    bool IList.Contains(object value) 
    { 
     return Contains((Zone)value); 
    } 

    int IList.IndexOf(object value) 
    { 
     return IndexOf((Zone)value); 
    } 

    void IList.Insert(int index, object value) 
    { 
     Insert(index, (Zone)value); 
    } 

    bool IList.IsFixedSize 
    { 
     get { return ((IList)_list).IsFixedSize; } 
    } 

    bool IList.IsReadOnly 
    { 
     get { return ((IList)_list).IsReadOnly; } 
    } 

    void IList.Remove(object value) 
    { 
     Remove((Zone)value); 
    } 

    object IList.this[int index] 
    { 
     get 
     { 
      return this[index]; 
     } 
     set 
     { 
      this[index] = (Zone)value; 
     } 
    } 

    void ICollection.CopyTo(Array array, int index) 
    { 
     CopyTo((Zone[])array, index); 
    } 

    bool ICollection.IsSynchronized 
    { 
     get { return ((ICollection)_list).IsSynchronized; } 
    } 

    object ICollection.SyncRoot 
    { 
     get { return ((ICollection)_list).SyncRoot; } 
    } 
} 
+0

是的,但NHibernate的需要一個IList,而不是一個列表。我沒有使用IList 的非通用IList實現嗎?或者我必須將其定義爲從IList派生,然後將其中的列表設置爲特定類型? –

+1

@Nathan - 對於可以進行強制轉換的代碼(as,is),它可以工作,*可以實現,但PropertyGrid代碼使用反射並且只是檢查IList是否直接由類實現。你可以保留泛型實現,但你只需要添加IList(並實現它) –

+0

好吧,我不是從IList派生出來的,而是從IList派生出來的,我從IList派生而來。在ZonesCollection的構造函數中,我將IList _list設置爲等於新列表()。這現在使用「...」按鈕列出PropertyGrid中的屬性區域;但是,集合編輯器中的區域屬性不顯示。有任何想法嗎? –

相關問題