2010-06-27 31 views
14

Tôi đang tìm kiếm INotifyCollectionChanged triển khai StackQueue. Tôi có thể lăn của riêng tôi nhưng tôi không muốn phát minh lại bánh xe.Stackable Stack and Queue

Trả lời

11

Với ngăn xếp và hàng đợi (gần như theo định nghĩa), bạn chỉ có quyền truy cập vào đầu ngăn xếp hoặc đầu hàng đợi. Đó là điều phân biệt chúng với số List. (Và như vậy, đó là lý do bạn chưa tìm thấy một)

Để trả lời mặc dù bạn có thể viết riêng của bạn, tôi sẽ làm điều đó bằng cách bắt nguồn từ ObservableCollection, sau đó trong trường hợp của một chồng thực hiện Push như một Insert tại offset 0 (và bật như chỉ số trả về 0 rồi RemoveAt chỉ số 0); hoặc với một hàng đợi, bạn chỉ có thể Add vào cuối danh sách đến Enqueue và lấy và xóa mục đầu tiên, như với ngăn xếp, cho Dequeue. Các hoạt động Insert, AddRemoveAt sẽ được gọi trên số ObservableCollection cơ bản và do đó gây ra sự kiện CollectionChanged được kích hoạt.


Bạn cũng có thể nói rằng bạn chỉ muốn ràng buộc hoặc được thông báo khi một mục bạn được cho là có quyền truy cập vào các thay đổi. Bạn sẽ tạo ra lớp riêng của bạn một lần nữa, có nguồn gốc từ stack hay Queue, và bắn các sự kiện CollectionChanged cách thủ công khi:

  • Something được đẩy lên hoặc popped từ một chồng
  • Something được dequeued từ một hàng đợi
  • Something được xếp hàng đợi trên hàng đợi, khi hàng đợi trước đây trống rỗng
+4

Tôi đề xuất phương pháp đầu tiên cho 'ObservableStack' - lấy được từ (hoặc tốt hơn, chứa) một' ObservableCollection'. Cách tiếp cận thứ hai sẽ tốt hơn cho 'ObservableQueue' - lấy từ' Queue' và thực hiện các thông báo của riêng bạn. Điều này là do bất kỳ 'ObservableQueue' được xây dựng trên một' List' sẽ có hiệu năng O (N) cho 'Enqueue' hoặc' Dequeue', trong khi mọi thứ khác sẽ là O (1). Điều này sẽ có tác động hiệu suất nếu có nhiều yếu tố trong hàng đợi. –

+0

Tôi quyết định tạo một lớp chung có thể quan sát được mà chỉ cần triển khai INotifyCollectionChanged. Các lớp gọi các phương thức Stack và Queue nội bộ và nâng cao sự kiện thích hợp. Việc tạo thành phần thừa kế thừa kế như các phương thức Stack và Queue không phải là ảo (mà tôi không hiểu tại sao). – Goran

26

Tôi gặp vấn đề tương tự và muốn chia sẻ giải pháp của mình cho người khác. Hy vọng điều này là hữu ích cho ai đó.

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

Xin chào. Có lỗi sau Pop() "Sự kiện Xóa bộ sưu tập phải chỉ định vị trí mục". anyway để sửa lỗi này? tnx –

+3

base.Count là vị trí mục thiếu cố định nó cho tôi. công khai mới ảo T Pop() { var item = base.Pop(); this.OnCollectionChanged (mới NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Remove, item, base.Count)); mục trả lại; } – uli78

+0

Tôi thích giải pháp này cho câu trả lời được chấp nhận. Nó cho phép bạn duy trì các kỳ vọng hiệu suất và ngữ nghĩa của một Stack/Queue, thay vì chỉ mô phỏng nó với một danh sách (ví dụ, đắt tiền để loại bỏ từ đầu, so với một Queue). – KChaloux

1

Rất giống với lớp trên, với một vài ngoại lệ:

  1. Publish prop thay đổi cho những thay đổi bộ sưu tập cho Đếm
  2. Override TrimExcess() b/c có thể ảnh hưởng Đếm
  3. Đã tạo sự kiện công khai để tôi không phải truyền tới giao diện
  4. Chuyển chỉ mục cho bộ sưu tập được thay đổi khi thích hợp
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)); 
     } 
    }