2010-06-27 16 views

Odpowiedz

11

Z stosami i kolejkami (prawie z definicji) masz dostęp tylko do górnej części stosu lub do głowy kolejki. To właśnie odróżnia je od List. (I tak, to dlaczego nie znalazłem jeden)

Aby odpowiedzieć choć można napisać własną rękę, chciałbym zrobić to poprzez wyprowadzenie z ObservableCollection, a następnie w przypadku stosu realizującego Push jako Insert w offsecie 0 (i pop jako zwracający indeks 0, następnie RemoveAt indeks 0); lub z kolejką można po prostu Add na końcu listy do Enqueue, a następnie pobrać i usunąć pierwszy element, jak ze stosu, dla Dequeue. Operacje Insert, Add i będą wywoływane na podstawie ObservableCollection, a więc powodują wyzwolenie zdarzenia CollectionChanged.


Możesz również powiedzieć, że chcesz po prostu powiązać lub otrzymać powiadomienie, gdy jeden produkt ma mieć dostęp do zmian. znowu będzie można tworzyć własne klasy, pochodzące ze stosu lub kolejki, a ognia zdarzenie CollectionChanged ręcznie, gdy:

  • Coś się nasunąć lub trzasnął ze stosu
  • Coś rozkolejkowywana z kolejki
  • Something jest umieszczany w kolejce w kolejce, gdy kolejka była poprzednio pusta
+4

Polecam pierwsze podejście do 'ObservableStack' - wywodzi się z (lub lepiej, zawiera)" ObservableCollection ". Drugie podejście byłoby lepsze dla 'ObservableQueue' - wywodzić się z' Queue' i implementować własne powiadomienia. Dzieje się tak dlatego, że każdy "ObservableQueue" zbudowany na "liście" będzie miał wydajność O (N) dla 'Enqueue' lub' Dequeue', podczas gdy wszystko inne będzie O (1). Miałoby to wpływ na wydajność, jeśli w kolejce jest wiele elementów. –

+0

Postanowiłem stworzyć ogólną obserwowalną klasę, która po prostu implementuje INotifyCollectionChanged. Klasy wywołują wewnętrzne metody Stack i Queue i podnoszą odpowiednie zdarzenie. Kompozycja uprzywilejowana nad dziedziczeniem, ponieważ metody stosu i kolejki nie są wirtualne (co nie pozwala mi zrozumieć dlaczego). – Goran

26

Wpadam na ten sam problem i chcę podzielić się moim rozwiązaniem z innymi. Mam nadzieję, że jest to pomocne dla kogoś.

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

Hi. Mając błąd po Pop() "Kolekcja Usuń wydarzenie musi określić pozycję przedmiotu." tak czy inaczej to naprawić? tnx –

+3

base.Count jako pozycja brakującej pozycji naprawiono dla mnie. publiczny nowy wirtualny T Pop() { var item = base.Pop(); this.OnCollectionChanged (new NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Remove, item, base.Count)); powrót przedmiot; } – uli78

+0

Preferuję to rozwiązanie do zaakceptowanej odpowiedzi. Pozwala zachować oczekiwania dotyczące wydajności i semantykę stosu/kolejki, zamiast jedynie symulować ją za pomocą listy (która na przykład jest kosztowna do usunięcia od początku w porównaniu do kolejki). – KChaloux

1

Bardzo podobna do powyższej klasy, z kilkoma wyjątkami:

  1. publikowania prop zmienionych zmian zbiórki hrabiego
  2. Zastąp TrimExcess() B/C, które mogłyby wpłynąć na hrabiego
  3. Udostępniono zdarzenia publiczne, więc nie muszę odlewać do interfejsu
  4. Wskaźnik trafień do zmiany w razie potrzeby
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)); 
     } 
    }