我正在寻找INotifyCollectionChanged
和Stack
的{{1}}实施。我可以自己动手,但我不想重新发明轮子。
答案 0 :(得分:31)
我遇到了同样的问题,希望与其他人分享我的解决方案。希望这对某人有帮助。
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; }
}
}
答案 1 :(得分:9)
使用堆栈和队列(几乎按定义),您只能访问堆栈顶部或队列头部。这是它们与List
的区别。 (所以,这就是你没找到的原因)
虽然你可以编写自己的答案,但我会通过派生ObservableCollection
来实现,然后在堆栈的情况下将Push
作为Insert
在偏移0处实现(并弹出作为返回索引0然后RemoveAt
索引0);或者使用队列,您可以Add
到列表末尾Enqueue
,然后抓取并删除第一项,就像堆栈一样,Dequeue
。将在基础Insert
上调用Add
,RemoveAt
和ObservableCollection
操作,因此会导致CollectionChanged
事件被触发。
您可能也会说,您只想在您应该有权访问的项目进行更改时绑定或得到通知。您将再次创建自己的类,派生自Stack或Queue,并在以下情况下手动触发CollectionChanged事件:
答案 2 :(得分:1)
与上述类非常相似,但有一些例外:
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;
}
}
答案 3 :(得分:0)
我意识到已经有一些答案了,但是我想我会给我一点点回报。我汇总了帖子和评论中提到的所有内容。很少有促使我这样做的事情:
Count
,Push
或Pop
时,INPC应始终为Clear
触发。Clear
,操作应为Reset
,并且集合更改事件的索引应设置为-1
(如果未设置,它将默认为默认值,因此其他帖子具有):.NET docs Push
/ Pop
,对于堆栈,动作应为Add
/ Remove
,并且集合更改事件的索引应为0
始终是并且唯一可以被操纵的第一项(请考虑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
}