2010-06-27 10 views
14

Estoy buscando una implementación INotifyCollectionChanged de Stack y Queue. Podría hacer mi propio pero no quiero reinventar la rueda.Observable Stack and Queue

Respuesta

11

Con pilas y colas (casi por definición) solo tiene acceso a la parte superior de la pila o cabeza de la cola. Es lo que los diferencia de List. (Y por lo tanto, es por eso que no ha encontrado uno)

Para responder a pesar de que podría escribir su propia, lo haría mediante la derivación de ObservableCollection, a continuación, en el caso de una pila aplicación del Push como Insert en el offset 0 (y pop como índice de retorno 0 luego RemoveAt índice 0); o con una cola puede simplemente Add hasta el final de la lista a Enqueue, y tomar y quitar el primer elemento, como con la pila, para Dequeue. Se llamaría a las operaciones Insert, Add y RemoveAt en el ObservableCollection subyacente y provocaría el desencadenamiento del evento CollectionChanged.


También puede ser que diga que simplemente quiere unirse o ser notificado cuando el único elemento que se supone que tienen acceso a los cambios. Se podría crear su propia clase de nuevo, derivado de la pila o cola, y desencadenar el evento CollectionChanged manualmente cuando:

  • Algo se empuja sobre o surgió a partir de una pila
  • Algo se quita de la cola de una cola
  • Algo se pone en la cola, cuando la cola estaba previamente vacía
+4

Recomiendo el primer acercamiento para 'ObservableStack' - deriva de (o mejor, contiene) un' ObservableCollection'. El segundo enfoque sería mejor para 'ObservableQueue': deriva de' Queue' e implementa tus propias notificaciones. Esto se debe a que cualquier 'ObservableQueue' construido en una' List' tendrá un rendimiento O (N) para 'Enqueue' o 'Dequeue', mientras que todo lo demás será O (1). Esto tendría un impacto en el rendimiento si hay muchos elementos en la cola. –

+0

Decidí hacer una clase observable genérica que simplemente implementara INotifyCollectionChanged. Las clases llaman a los métodos internos de pila y cola y generan el evento apropiado. Favorecer la composición sobre la herencia, ya que los métodos Stack y Cola no son virtuales (lo que me cuesta entender por qué). – Goran

26

Me encuentro con el mismo problema y quiero compartir mi solución con otros. Espero que esto sea útil para alguien.

public class ObservableStack<T> : Stack<T>, INotifyCollectionChanged, INotifyPropertyChanged 
{ 
    public ObservableStack() 
    { 
    } 

    public ObservableStack(IEnumerable<T> collection) 
    { 
     foreach (var item in collection) 
      base.Push(item); 
    } 

    public ObservableStack(List<T> list) 
    { 
     foreach (var item in list) 
      base.Push(item); 
    } 


    public new virtual void Clear() 
    { 
     base.Clear(); 
     this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
    } 

    public new virtual T Pop() 
    { 
     var item = base.Pop(); 
     this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item)); 
     return item; 
    } 

    public new virtual void Push(T item) 
    { 
     base.Push(item); 
     this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); 
    } 


    public virtual event NotifyCollectionChangedEventHandler CollectionChanged; 


    protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
    { 
     this.RaiseCollectionChanged(e); 
    } 

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) 
    { 
     this.RaisePropertyChanged(e); 
    } 


    protected virtual event PropertyChangedEventHandler PropertyChanged; 


    private void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e) 
    { 
     if (this.CollectionChanged != null) 
      this.CollectionChanged(this, e); 
    } 

    private void RaisePropertyChanged(PropertyChangedEventArgs e) 
    { 
     if (this.PropertyChanged != null) 
      this.PropertyChanged(this, e); 
    } 


    event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged 
    { 
     add { this.PropertyChanged += value; } 
     remove { this.PropertyChanged -= value; } 
    } 
} 
+2

Hola. Tener un error después de Pop() "El evento Collection Remove debe especificar la posición del elemento". ¿Cualquier forma de arreglar esto? tnx –

+3

base.Count como la posición del artículo faltante lo arregló para mí. public new virtual T Pop() { var item = base.Pop(); this.OnCollectionChanged (nuevo NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Remove, item, base.Count)); artículo devuelto; } – uli78

+0

Prefiero esta solución a la respuesta aceptada. Le permite mantener las expectativas de rendimiento y la semántica de Stack/Queue, en lugar de simplemente simularlo con una lista (que, por ejemplo, es caro de eliminar desde el principio, en comparación con una cola). – KChaloux

1

Muy similar a la clase anterior, con algunas excepciones:

  1. Publish prop cambiado para cambios de recogida para el recuento de
  2. Override TrimExcess() b/c que podría afectar Count
  3. Hechos públicos para que no tenga que enviar a la interfaz
  4. Pasa el índice a la colección cambiado cuando corresponde
public class ObservableStack : Stack, INotifyPropertyChanged, INotifyCollectionChanged 
    { 
     public ObservableStack(IEnumerable collection) : base(collection) {} 
     public ObservableStack() { } 

     public event PropertyChangedEventHandler PropertyChanged = delegate { }; 
     public event NotifyCollectionChangedEventHandler CollectionChanged = delegate { }; 

     protected virtual void OnCollectionChanged(NotifyCollectionChangedAction action, List items, int? index = null) 
     { 
     if (index.HasValue) 
     { 
      CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, items, index.Value)); 
     } 
     else 
     { 
      CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, items)); 
     } 
     OnPropertyChanged(ClrExtensions.PropertyName(() => Count)); 
     } 

     protected virtual void OnPropertyChanged(string propName) 
     { 
     PropertyChanged(this, new PropertyChangedEventArgs(propName)); 
     } 

     public new virtual void Clear() 
     { 
     base.Clear(); 
     OnCollectionChanged(NotifyCollectionChangedAction.Reset, null); 
     } 

     public new virtual T Pop() 
     { 
     var result = base.Pop(); 
     OnCollectionChanged(NotifyCollectionChangedAction.Remove, new List() { result }, base.Count); 
     return result; 
     } 

     public new virtual void Push(T item) 
     { 
     base.Push(item); 
     OnCollectionChanged(NotifyCollectionChangedAction.Add, new List() { item }, base.Count - 1); 
     } 

     public new virtual void TrimExcess() 
     { 
     base.TrimExcess(); 
     OnPropertyChanged(ClrExtensions.PropertyName(() => Count)); 
     } 
    }