19

とのINotifyCollectionChanged実装を探しています。私は自分で転がることはできましたが、車輪の再発明をしたくありません。StackQueue

4

4 に答える 4

34

同じ問題が発生し、自分の解決策を他の人と共有したいと思います。これが誰かに役立つことを願っています。

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; }
    }
}
于 2011-06-05T19:15:41.870 に答える
9

スタックとキュー(ほとんど定義上)では、スタックの最上位またはキューの先頭にしかアクセスできません。それがそれらをと区別するものListです。(そして、それがあなたがそれを見つけられなかった理由です)

あなたがあなた自身を書くことができるけれども答えるために、私はから派生することによってそれをします ObservableCollection、そしてスタックの場合はオフセット0でとしPushてを実装します(そしてインデックス0を返し、次にインデックス0としてポップします); または、キューを使用して、リストの最後まで移動し、スタックの場合と同様に、最初の項目を取得して削除することもできます。、および操作は基になる操作で呼び出されるため、イベントが発生します。InsertRemoveAtAddEnqueueDequeueInsertAddRemoveAtObservableCollectionCollectionChanged


また、アクセスできるはずの1つのアイテムが変更されたときに、バインドまたは通知を受け取るだけでよいと言っている場合もあります。StackまたはQueueから派生した独自のクラスを再度作成し、次の場合にCollectionChangedイベントを手動で発生させます。

  • 何かがスタックにプッシュまたはポップされます
  • キューから何かがデキューされます
  • キューが以前に空だったときに、何かがキューにキューイングされています
于 2010-06-27T11:15:59.767 に答える
4

私はすでにいくつかの答えがあることを理解していますが、私は私と一緒に少しお返しするだろうと考えました。私は投稿とコメントで言及されたすべてをまとめました。これを行う動機となったものはほとんどありませんでした。

  • INPCは、投稿の1つに記載されているように、、、またはが呼び出されCountたときPushに常に起動する必要があります。PopClear
  • の場合Clear、アクションはである必要がResetあり、コレクション変更イベントのインデックスはに設定されている必要があります-1(設定されていない場合はデフォルトでデフォルトになるため、他の投稿にそれがあります):.NET docs
  • Push/の場合Pop、アクションは/である必要がAddありRemove、コレクション変更イベントのインデックスは、0常に操作できる最初のアイテムのみであるというスタックのインデックスである必要があります(think stack.GetEnumerator().MoveNext())。
  • ロジックをオーバーライドする理由がないため、呼び出しStack<T>で使用可能な3つのコンストラクターすべてを公開し、呼び出しを使用します。base()

結果:

public class ObservableStack<T> : Stack<T>, INotifyCollectionChanged, INotifyPropertyChanged
{
    #region Constructors

    public ObservableStack() : base() { }

    public ObservableStack(IEnumerable<T> collection) : base(collection) { }

    public ObservableStack(int capacity) : base(capacity) { }

    #endregion

    #region Overrides

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

        return item;
    }

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

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

    #endregion

    #region CollectionChanged

    public virtual event NotifyCollectionChangedEventHandler CollectionChanged;

    protected virtual void OnCollectionChanged(NotifyCollectionChangedAction action, T item)
    {
        CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(
            action
            , item
            , item == null ? -1 : 0)
        );

        OnPropertyChanged(nameof(Count));
    }

    #endregion

    #region PropertyChanged

    public virtual event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string proertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(proertyName));
    }

    #endregion
}
于 2019-05-16T23:46:11.373 に答える
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(GetPropertyName(() => 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(GetPropertyName(() => Count));
      }

String GetPropertyName(Expression> propertyId)
{
   return ((MemberExpression)propertyId.Body).Member.Name;
}

    }
于 2015-02-02T15:31:40.463 に答える