2009-12-08 7 views
1

J'ai une classe appelée Client, qui est une sous-classe de Configurable.ObservableCollection wrapper à convertir en un type de base

J'ai un ObservableCollection<Client> que j'ai besoin d'afficher comme ObservableCollection<Configurable>. Cela me permettra d'accéder à la liste à partir d'un code de génération de mise en page générale. Il doit également me permettre d'effacer la liste et d'ajouter des éléments à la liste. Bien sûr, lors de l'ajout d'éléments à la liste, il doit effectuer une vérification du type d'exécution pour vérifier que l'élément général ajouté (Configurable) est du type approprié (Client). J'imagine une classe appelée ObservableSurrogateCollection<T>. T est la classe générale (Configurable). Vous devez le construire en lui attribuant un ObservableCollection<T2>, où T2 est une sous-classe de T. Vous pouvez y effectuer une liaison de données et tous les événements modifiés de la collection dans la liste encapsulée sont correctement routés (dans les deux directions).

Est-ce que cela existe? Est-ce que ce n'est pas quelque chose que je devrais faire? Je pense que j'ai lu que .NET 4.0 supportera une telle fonctionnalité au niveau de la langue?

J'ai regardé ces options:

  • ReadOnlyObservableCollection<T>. C'est vraiment proche. Cependant, parce qu'il est en lecture seule, je ne peux pas ajouter ou effacer les éléments. Un code non générique ObservableCollection. Je n'arrive pas à le trouver, s'il existe.

Merci d'avance pour toute aide!

Répondre

2

Non, cela n'existe pas AFAIK, mais ne devrait pas être difficile à mettre en œuvre; Bien entendu, il implique les nuances de la variance, de sorte que votre collection doit s'attendre à des problèmes de moulage lors de l'attribution/l'ajout. Notez que tableaux (T[]) déjà agir comme ceci (tableaux de types de référence ont le soutien de la variance, avec la vérification typecast etc), mais vous ne pouvez pas ajouter à un tableau, et il ne déclenche pas les événements de changement.

Pour mettre en œuvre ce serait en grande partie un travail d'encapsulation; La construction d'un objet (lors de la liaison de données à de nouvelles lignes) serait le plus difficile et pourrait vous obliger à ajouter des interfaces supplémentaires.

4.0 n'a rien à ajouter ici: What C# 4.0 covariance *doesn't* do

Non testé, mais:

public class ObservableCollection<TBase, TActual> : IList<TBase>, IBindingList, INotifyCollectionChanged 
    where TBase : class 
    where TActual : class, TBase 
{ 

    private readonly ObservableCollection<TActual> innerList; 

    public ObservableCollection() 
     : this((IEnumerable<TActual>)null) {} 
    public ObservableCollection(IEnumerable<TBase> data) 
     : this(data == null ? null : data.Cast<TActual>()) {} 
    public ObservableCollection(IEnumerable<TActual> data) 
    { 
     innerList = data == null ? new ObservableCollection<TActual>() 
      : new ObservableCollection<TActual>(data); 
     innerList.CollectionChanged += new NotifyCollectionChangedEventHandler(innerList_CollectionChanged); 
    } 

    void innerList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     ListChangedEventHandler handler = ListChanged; 
     if(handler != null) { 
      ListChangedEventArgs args = null; 
      switch (e.Action) 
      { 
       case NotifyCollectionChangedAction.Add: 
        args = new ListChangedEventArgs(ListChangedType.ItemAdded, e.NewStartingIndex); 
        break; 
       case NotifyCollectionChangedAction.Remove: 
        args = new ListChangedEventArgs(ListChangedType.ItemDeleted, e.OldStartingIndex); 
        break; 
       case NotifyCollectionChangedAction.Reset: 
        args = new ListChangedEventArgs(ListChangedType.Reset, -1); 
        break; 
       case NotifyCollectionChangedAction.Replace: 
        args = new ListChangedEventArgs(ListChangedType.ItemChanged, e.NewStartingIndex); 
        break; 
       case NotifyCollectionChangedAction.Move: 
        args = new ListChangedEventArgs(ListChangedType.ItemMoved, e.NewStartingIndex, e.OldStartingIndex); 
        break; 
      } 
      if(args != null) handler(this, args); 
     } 
     NotifyCollectionChangedEventHandler handler2 = CollectionChanged; 
     if (handler2 != null) handler2(this, e); 
    } 

    public void AddIndex(PropertyDescriptor property) {} 

    public object AddNew() 
    { 
     TActual obj = (TActual)Activator.CreateInstance(typeof(TActual)); 
     Add(obj); 
     return obj; 
    } 

    public bool AllowEdit { get { return !IsReadOnly; } } 
    public bool AllowNew { get { return !IsFixedSize; } } 
    public bool AllowRemove { get { return !IsFixedSize; } } 

    public void ApplySort(PropertyDescriptor property, ListSortDirection direction) 
    { 
     throw new System.NotImplementedException(); 
    } 

    public int Find(PropertyDescriptor property, object key) 
    { 
     throw new System.NotImplementedException(); 
    } 

    public bool IsSorted { get { return false; } } 

    public event ListChangedEventHandler ListChanged; 
    public event NotifyCollectionChangedEventHandler CollectionChanged; 

    public void RemoveIndex(PropertyDescriptor property) { } 

    public void RemoveSort() 
    { 
     throw new System.NotImplementedException(); 
    } 

    public ListSortDirection SortDirection 
    { 
     get { return ListSortDirection.Ascending; } 
    } 

    public PropertyDescriptor SortProperty 
    { 
     get { throw new System.NotImplementedException(); } 
    } 

    public bool SupportsChangeNotification { get { return true; } } 
    public bool SupportsSearching { get { return false; } } 
    public bool SupportsSorting { get { return false; } } 

    int IList.Add(object value) 
    { 
     int index = innerList.Count; 
     Add((TBase)value); 
     return index; 
    } 
    public void Add(TBase value) 
    { 
     innerList.Add((TActual)value); 
    } 

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

    bool IList.Contains(object value) 
    { 
     return Contains((TBase)value); 
    } 
    public bool Contains(TBase value) 
    { 
     return innerList.Contains((TActual)value); 
    } 

    int IList.IndexOf(object value) 
    { 
     return IndexOf((TBase)value); 
    } 
    public int IndexOf(TBase value) 
    { 
     return innerList.IndexOf((TActual)value); 
    } 

    void IList.Insert(int index, object value) 
    { 
     Insert(index, (TBase)value); 
    } 
    public void Insert(int index, TBase value) 
    { 
     innerList.Insert(index, (TActual)value); 
    } 

    public bool IsFixedSize 
    { 
     get { return ((IList)innerList).IsFixedSize; } 
    } 

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

    void IList.Remove(object value) 
    { 
     Remove((TBase)value); 
    } 
    public bool Remove(TBase value) 
    { 
     return innerList.Remove((TActual)value); 
    } 

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

    object IList.this[int index] 
    { 
     get { return innerList[index]; } 
     set { innerList[index] = (TActual)value; } 
    } 
    public TBase this[int index] 
    { 
     get { return innerList[index]; } 
     set { innerList[index] = (TActual)value; } 
    } 

    void ICollection.CopyTo(System.Array array, int index) 
    { 
     ((IList)innerList).CopyTo(array, index); 
    } 
    public void CopyTo(TBase[] array, int index) 
    { 
     innerList.CopyTo((TActual[])array, index); 
    } 

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

    public bool IsSynchronized 
    { 
     get { return ((IList)innerList).IsSynchronized; } 
    } 

    public object SyncRoot 
    { 
     get { return ((IList)innerList).SyncRoot; } 
    } 

    public IEnumerator<TBase> GetEnumerator() 
    { 
     return innerList.Cast<TBase>().GetEnumerator(); 
    } 
    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return innerList.GetEnumerator(); 
    } 
}