可观察的堆栈和队列

发布于 2024-09-07 04:25:26 字数 115 浏览 13 评论 0原文

我正在寻找 StackQueueINotifyCollectionChanged 实现。我可以自己动手,但我不想重新发明轮子。

I'm looking for an INotifyCollectionChanged implementation of Stack and Queue. I could roll my own but I don't want to reinvent the wheel.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

猥︴琐丶欲为 2024-09-14 04:25: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; }
    }
}

I run into the same issue and want to share my solution to others. Hope this is helpful to someone.

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; }
    }
}
生生漫 2024-09-14 04:25:26

使用堆栈和队列(几乎根据定义),您只能访问堆栈顶部或队列头部。这就是它们与 List 的区别。 (所以,这就是为什么你还没有找到一个)

要回答,尽管你可以编写自己的,我会通过从 ObservableCollection 派生来完成,然后在实现 的堆栈的情况下Push 作为 Insert 在偏移量 0 处(并弹出作为返回索引 0,然后返回 RemoveAt 索引 0);或者使用队列,您可以将Add添加到列表末尾以Enqueue,然后抓取并删除第一个项目,就像堆栈一样,用于Dequeue。将在基础 ObservableCollection 上调用 InsertAddRemoveAt 操作,从而导致 CollectionChanged 事件被触发。


您也可能会说,您只是想在您应该有权访问的一项发生更改时进行绑定或收到通知。您可以再次创建自己的类(从 Stack 或 Queue 派生),并在以下情况下手动触发 CollectionChanged 事件:

  • 某些内容被推入堆栈或从堆栈中弹出
  • 某些内容从队列中出列
  • 当队列先前为空时,某些内容在队列中排队

With Stacks and Queues (almost by definition) you only have access to the top of the stack or head of the queue. It's what differentiates them from a List. (and so, that's why you haven't found one)

To answer though you could write your own, I would do it by deriving from ObservableCollection, then in the case of a stack implementing the Push as an Insert at offset 0 (and pop as returning index 0 then RemoveAt index 0); or with a queue you could just Add to the end of the list to Enqueue, and the grab and remove the first item, as with the stack, for Dequeue. The Insert, Add and RemoveAt operations would be called on the underlying ObservableCollection and so cause the CollectionChanged event to be fired.


You might also be saying that you simply want to bind or be notified when the one item you are supposed to have access to changes. You would create your own class again, derived from Stack or Queue, and fire the CollectionChanged event manually when:

  • Something is pushed onto or popped from a stack
  • Something is dequeued from a queue
  • Something is queued on the queue, when the queue was previously empty
恋你朝朝暮暮 2024-09-14 04:25:26

我意识到已经有一些答案,但我想我会回馈一些我的答案。我将帖子和评论中提到的所有内容放在一起。有几件事促使我这样做:

  • PushPopClearCount code> 被调用,如其中一篇文章中提到的。
  • 对于Clear,操作应为Reset,并且集合更改事件的索引应设置为-1(如果不是,它将默认为设置以便其他帖子也有该设置): .NET docs
  • 对于 Push/Pop,操作应为 Add/Remove 并且集合的索引已更改对于堆栈来说,事件应该是0,因为它始终是并且只是第一个可以操作的项目(想想stack.GetEnumerator().MoveNext())。
  • 公开了 Stack 中可用的所有 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 propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

I realize there are already a few answers but figured I would give back a little with mine. I put together everything mentioned in the posts and comments. There were few things that motivated me to do this:

  • INPC should always fire for Count when Push, Pop, or Clear are called, as mentioned in one of the posts.
  • For Clear, action should be Reset and index for the collection change event should be set to -1 (which it will default to anyway if not set so the other posts have that): .NET docs
  • For Push/Pop, action should be Add/Remove and index for the collection changed event should be 0 for a stack being that it is always and only the first item that can be maniuplated (think stack.GetEnumerator().MoveNext()).
  • Exposed all 3 constructors available in Stack<T> and use base() calls since there is no reason to override the logic.

Results in:

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 propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}
笔芯 2024-09-14 04:25:26

与上面的类非常相似,但有一些例外:

  1. Publish 属性更改为 Count
  2. Override TrimExcess() b/c 的集合更改,这可能会影响 Count
  3. Made 事件公开,因此我不必强制转换到接口
  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;
}

    }

Very similar to the above class, with a few exceptions:

  1. Publish prop changed for collection changes for Count
  2. Override TrimExcess() b/c that could affect Count
  3. Made events public so I don't have to cast to the interface
  4. Passes index to collectionchanged when appropriate
    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;
}

    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文