0

내가이 시점에 도달 한 방법에 대한 약간의 기록을 제공하겠습니다.PropertyGrid - IList에서 파생 한 속성 <T>, 사용자가 PropertyGrid에 항목을 추가/편집/제거 할 수 있도록 추가하려면 어떻게해야합니까?

원래 클래스에서 파생 된 CollectionsBase에서 파생 된 Property가 있었으며 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 내 메인 클래스에서

는 I는 속성으로 정의 이 클래스가 CollectionsBase에서 파생되었을 때 PropertyDescriptor는 정상적으로 작동했지만 이제는 속성 이름에 "..."단추가없는 클래스 이름 ZoneCollection 만 표시됩니다. dd/편집/목록에서 항목을 제거하십시오.

IList에서 상속받은이 기능이 제대로 작동하지 않습니다. 무엇이 잘못 되었습니까?

[TypeConverter(typeof(ExpandableObjectConverter))] 

ZoneCollection의 시작에, 내가 확장 가능한 트리에 나와있는 목록의 항목을 얻을 수 있지만, 내가 무엇을 찾고 아니에요 :

나는 추가합니다. 어디에서 "..."버튼을 클릭하면 CollectionBase 대신 IList에서 상속 받았을 때 컬렉션의 항목을 추가/편집/제거 할 수있는 팝업 창이 열렸습니까?

답변

3

PropertyGrid는 심술 궂은 짐승입니다. 일반이 아닌 일반 구현 인 IList 명시 적 구현이 필요합니다.

사이트 메모로 ZoneCollection을 List<Zone>에서 직접 파생시킬 수 있으며이 PropertyGrid 문제와 관련하여 ICustomTypeDescriptor/PropertyDescriptor가 필요하지 않습니다. 여기

가 작동하는 것 같다 구현입니다 :

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 을 사용하여 non-gneric IList 구현을 사용하지 않았습니까? 또는 IList에서 파생 된 것으로 정의해야하고 내 목록을 특정 유형으로 설정해야합니까? –

+1

@Nathan - 캐스트 (as, is)를 수행하는 코드의 경우 작동하지만 * 구현되지만 PropertyGrid 코드는 리플렉션을 사용하고 IList가 클래스에 의해 직접 구현되었는지 검사합니다. 제네릭 구현을 유지할 수 있지만 IList를 추가하고 구현해야합니다. –

+0

좋습니다 IList 에서 파생되는 대신 IList에서 파생되었습니다. ZonesCollection의 생성자에서 IList _list를 새 List ()과 동일하게 설정했습니다.이제 "..."버튼을 사용하여 PropertyGrid의 등록 정보 영역이 나열됩니다. 그러나 컬렉션 편집기에서 영역의 속성은 표시되지 않습니다. 어떤 아이디어? –