Note that there are some explanatory texts on larger screens.

plurals
  1. POPropertyGrid - Property derived from IList<T>, How do I add to the PropertyGrid so user can Add/Edit/Remove items
    text
    copied!<p>Let me provide a bit of a history as to how I've reached this point.</p> <p>I originally had a Property within my class that derived from CollectionsBase and had this collection mapped to the PropertyGrid and the user could Add/Edit/Remove items from the list at will.</p> <p>However, I couldn't map the CollectionsBase with NHibernate, thus I had to scrap my initial implementation and instead of deriving from CollectionsBase, I had the class derive from IList.</p> <p>Now I can map to NHibernate, but I am unable to edit the collection via the PropertyGrid.</p> <p>I need some help getting the 2 to play nice with each other.</p> <p>In my main class I have a property defined as:</p> <pre><code> public virtual ZoneCollection Zones { get { return zones; } set { zones = value; } } </code></pre> <p>My Zone Collection that inherits IList is defined as follows:</p> <pre><code>public class ZoneCollection : IList&lt;Zone&gt;, ICustomTypeDescriptor { private IList&lt;Zone&gt; _list; public IList&lt;Zone&gt; _List { get { return _list; } } public ZoneCollection() { _list = new List&lt;Zone&gt;(); } #region Implementation of IEnumerable public IEnumerator&lt;Zone&gt; GetEnumerator() { return _list.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion #region Implementation of ICollection&lt;Zone&gt; 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&lt;Zone&gt; 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; } /// &lt;summary&gt; /// Called to get the properties of this type. Returns properties with certain /// attributes. this restriction is not implemented here. /// &lt;/summary&gt; /// &lt;param name="attributes"&gt;&lt;/param&gt; /// &lt;returns&gt;&lt;/returns&gt; public PropertyDescriptorCollection GetProperties(Attribute[] attributes) { return GetProperties(); } /// &lt;summary&gt; /// Called to get the properties of this type. /// &lt;/summary&gt; /// &lt;returns&gt;&lt;/returns&gt; 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 &lt; 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 } /// &lt;summary&gt; /// Summary description for CollectionPropertyDescriptor. /// &lt;/summary&gt; 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; } } </code></pre> <p>}</p> <p>Now, my ICustomTypeDescriptor and PropertyDescriptor worked fine when this class derived from CollectionsBase, but now it just shows the class name ZoneCollection in the property name without the "..." button to add/edit/remove the items from the list.</p> <p>What am I doing wrong now that it is inherited from IList that this isn't working?</p> <p>If I add:</p> <pre><code>[TypeConverter(typeof(ExpandableObjectConverter))] </code></pre> <p>To the beginning of the ZoneCollection, I get the items in the list listed in an expandable tree, but that's not what I am looking for. Where did the "..." button go that opened up a popup window that enabled me to add/edit/remove the items in the collection when I inherited from IList instead of CollectionBase?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload