2010-06-27 3 views

답변

11

스택 및 대기열 (거의 정의 됨)을 사용하면 스택 맨 또는 대기열 맨 위에 만 액세스 할 수 있습니다. 그것들은 List과 구별됩니다. 나는 오프셋 Insert에서와 Push를 구현하는 스택의 경우 다음 ObservableCollection에서 파생에 의해 그것을 할 것입니다, 당신이 당신의 자신을 쓸 수 있지만

가 대답하기 위해 (당신이 하나를 찾을 수없는 이유 때문에, 그건) 0 (그리고 인덱스가 0으로 돌아 오자 팝 후 RemoveAt 인덱스 0); 또는 대기열을 사용하면 목록의 끝에 AddEnqueue으로 가져올 수 있으며 스택과 마찬가지로 Dequeue의 첫 번째 항목을 잡고 제거 할 수 있습니다. Insert, AddRemoveAt 작업은 기본 ObservableCollection에서 호출되므로 CollectionChanged 이벤트가 발생합니다.


변경 사항에 액세스 할 것으로 예상되는 항목이 하나 일 때 바인드하거나 알림을 보내려는 것일 수도 있습니다. 당신은 스택 또는 큐에서 파생 된, 다시 자신의 클래스를 만들 때 수동으로 CollectionChanged 이벤트를 해고 :

  • 뭔가
  • 뭔가 큐
  • 뭔가 대기열에서 제거 된 스택에서 푸시 또는 팝됩니다 대기열이 이전에 비어있을 때 대기열에 대기 중임
+4

"ObservableStack"에 대한 첫 번째 접근 방식을 권장합니다. ObservableCollection에서 파생되었거나 더 좋았습니다. 두 번째 접근법은'ObservableQueue'를 위해 더 좋을 것입니다 -'Queue'에서 파생시키고 여러분 자신의 통지를 구현하십시오. 왜냐하면'List'에 내장 된'ObservableQueue'는'Enqueue' 또는'Dequeue'에 대해 O (N) 성능을 가지기 때문에 다른 모든 것은 O (1) 일 것입니다. 대기열에 많은 요소가 있으면 성능에 영향을 미칩니다. –

+0

간단히 INotifyCollectionChanged를 구현하는 일반적인 관찰 가능한 클래스를 만들기로했습니다. 클래스는 내부 스택 및 대기열 메서드를 호출하고 적절한 이벤트를 발생시킵니다. Stack과 Queue 메소드가 상속이 아닌 상속에 비해 컴포지션을 선호하는 이유는 무엇인지 이해하는 데 어려움이 있습니다. – Goran

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 제거 이벤트가 항목 위치를 지정해야합니다." 어쨌든이 문제를 해결할 수 있습니까? tnx –

+3

base.Count 누락 된 항목 위치로 나를 위해 그것을 고정. public 새 가상 T Pop() { var item = base.Pop(); this.OnCollectionChanged (새 NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Remove, item, base.Count))); 반품 항목 : } – uli78

+0

나는 받아 들인 대답에이 해결책을 선호한다. 이 기능을 사용하면 스택 (대기열에 비해 처음부터 제거하는 데 비용이 많이 드는)을 사용하여 스택/큐의 성능 예상치와 의미를 유지 관리 할 수 ​​있습니다. – KChaloux

1

몇 가지 예외를 제외하고, 위의 클래스와 매우 유사한

  1. 가 게시 소품이 영향을 미칠 수있는 카운트
  2. 무시 TrimExcess() B/C에 대한 수집 변화를 변경 카운트
  3. 이벤트를 공개 했으므로 인터페이스에 전송할 필요가 없습니다.
  4. 적절한 시점에 collectionchanged에 인덱스를 전달하십시오.
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)); 
     } 
    }