2010-06-27 88 views

回答

11

使用堆棧和隊列(幾乎按定義),您只能訪問堆棧頂部或隊列頭部。這是區別於List。 (所以,這就是爲什麼你還沒有找到一個)

要回答雖然你可以寫你自己的,我會從ObservableCollection得出這樣做,那麼在執行PushInsert在堆棧偏移的情況下, 0(並且彈出作爲返回索引0,然後RemoveAt索引0);或者可以使用隊列Add到列表末尾Enqueue,然後抓取並刪除第一項,如堆棧中的Dequeue。將在底層ObservableCollection上調用Insert,AddRemoveAt操作,從而導致CollectionChanged事件被觸發。


你可能也會說,你只是想綁定或通知,當你應該有一個項目可以訪問更改。你會再次創建自己的類,從堆棧或隊列導出,並手動觸發CollectionChanged事件時:

  • 東西推到或彈出從堆棧
  • 東西從隊列
  • 東西離隊在隊列中排隊時,隊列先前爲空
+4

我推薦「ObservableStack」的第一種方法 - 派生自(或更好的,包含)一個ObservableCollection。第二種方法對'ObservableQueue'會更好 - 從'Queue'派生並實現您自己的通知。這是因爲構建在List上的任何ObservableQueue對於Enqueue或Dequeue都具有O(N)性能,而其他所有內容都是O(1)。如果隊列中有很多元素,這會對性能產生影響。 – 2010-06-27 13:53:06

+0

我決定做一個簡單實現INotifyCollectionChanged的通用可觀測類。類調用內部堆棧和隊列方法,並引發相應的事件。由於堆棧和隊列方法不是虛擬的(我無法理解爲什麼),所以對繼承有利。 – Goran 2010-06-27 15:53:23

26

我遇到了同樣的問題,並希望將我的解決方案分享給其他人。希望這對某人有幫助。

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

嗨。在Pop()之後出現錯誤「Collection Remove事件必須指定項目位置」。有任何解決這個問題的方法嗎? tnx – 2012-11-24 06:02:52

+3

base.Count作爲缺失項目的位置固定它給我。() public new virtual T Pop() var item = base.Pop(); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove,item,base.Count)); 退貨項目; } – uli78 2013-01-15 06:33:21

+0

我更喜歡這個解決方案的接受答案。它可以讓你保持堆棧/隊列的性能預期和語義,而不僅僅是用一個列表來模擬它(例如,與一個隊列相比,從一開始就很昂貴)。 – KChaloux 2014-04-24 18:29:23

1

非常類似上面的類,有一些例外:

  1. 發佈道具變更爲計數
  2. 覆蓋TrimExcess()B/C,可能會影響集合改變計數
  3. 公開發布活動,因此我無需投放到界面
  4. 合適時通過索引更改
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)); 
     } 
    }