讓我提供一些關於我如何達到這一點的歷史記錄。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繼承時添加/編輯/刪除集合中的項目?
是的,但NHibernate的需要一個IList,而不是一個列表。我沒有使用IList的非通用IList實現嗎?或者我必須將其定義爲從IList派生,然後將其中的列表設置爲特定類型? –
@Nathan - 對於可以進行強制轉換的代碼(as,is),它可以工作,*可以實現,但PropertyGrid代碼使用反射並且只是檢查IList是否直接由類實現。你可以保留泛型實現,但你只需要添加IList(並實現它) –
好吧,我不是從IList派生出來的,而是從IList派生出來的,我從IList派生而來。在ZonesCollection的構造函數中,我將IList _list設置爲等於新列表()。這現在使用「...」按鈕列出PropertyGrid中的屬性區域;但是,集合編輯器中的區域屬性不顯示。有任何想法嗎? –