我正在寻找and的INotifyCollectionChanged
实现。我可以自己动手,但我不想重新发明轮子。Stack
Queue
问问题
20331 次
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
,然后在堆栈实现的情况下,Push
作为Insert
偏移量 0 (并弹出作为返回索引 0,然后返回索引RemoveAt
0);或者使用队列,您可以只Add
到列表的末尾Enqueue
,然后抓取并删除第一个项目,就像堆栈一样,for Dequeue
。Insert
和操作将在底层调用Add
,因此导致事件被触发。RemoveAt
ObservableCollection
CollectionChanged
您可能还说,您只是想在您应该有权访问的一项更改时绑定或收到通知。您将再次创建自己的类,派生自 Stack 或 Queue,并在以下情况下手动触发 CollectionChanged 事件:
- 某些东西被压入堆栈或从堆栈中弹出
- 某物从队列中出列
- 当队列先前为空时,队列中已排队
于 2010-06-27T11:15:59.767 回答
4
我意识到已经有一些答案,但我想我会回馈一点。我将帖子和评论中提到的所有内容放在一起。有几件事促使我这样做:
- 如其中一篇文章所述, INPC 应始终在、或被调用
Count
时开火。Push
Pop
Clear
- 对于
Clear
,操作应该是Reset
,并且集合更改事件的索引应该设置为-1
(如果未设置,它将默认为无论如何其他帖子都有):.NET docs - 对于
Push
/Pop
,操作应该是Add
/Remove
并且集合更改事件的索引应该是0
堆栈,因为它始终是并且只有第一个可以操作的项目(想想stack.GetEnumerator().MoveNext()
)。 - 公开所有 3 个可用的构造函数
Stack<T>
并使用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
与上面的类非常相似,但有一些例外:
- 针对 Count 的集合更改更改了发布道具
- 覆盖可能影响计数的 TrimExcess() b/c
- 将事件公开,因此我不必投射到界面
- 适当时将索引传递给 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 回答