とのINotifyCollectionChanged
実装を探しています。私は自分で転がることはできましたが、車輪の再発明をしたくありません。Stack
Queue
4 に答える
同じ問題が発生し、自分の解決策を他の人と共有したいと思います。これが誰かに役立つことを願っています。
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; }
}
}
スタックとキュー(ほとんど定義上)では、スタックの最上位またはキューの先頭にしかアクセスできません。それがそれらをと区別するものList
です。(そして、それがあなたがそれを見つけられなかった理由です)
あなたがあなた自身を書くことができるけれども答えるために、私はから派生することによってそれをします ObservableCollection
、そしてスタックの場合はオフセット0でとしPush
てを実装します(そしてインデックス0を返し、次にインデックス0としてポップします); または、キューを使用して、リストの最後まで移動し、スタックの場合と同様に、最初の項目を取得して削除することもできます。、および操作は基になる操作で呼び出されるため、イベントが発生します。Insert
RemoveAt
Add
Enqueue
Dequeue
Insert
Add
RemoveAt
ObservableCollection
CollectionChanged
また、アクセスできるはずの1つのアイテムが変更されたときに、バインドまたは通知を受け取るだけでよいと言っている場合もあります。StackまたはQueueから派生した独自のクラスを再度作成し、次の場合にCollectionChangedイベントを手動で発生させます。
- 何かがスタックにプッシュまたはポップされます
- キューから何かがデキューされます
- キューが以前に空だったときに、何かがキューにキューイングされています
私はすでにいくつかの答えがあることを理解していますが、私は私と一緒に少しお返しするだろうと考えました。私は投稿とコメントで言及されたすべてをまとめました。これを行う動機となったものはほとんどありませんでした。
- INPCは、投稿の1つに記載されているように、、、またはが呼び出され
Count
たときPush
に常に起動する必要があります。Pop
Clear
- の場合
Clear
、アクションはである必要がReset
あり、コレクション変更イベントのインデックスはに設定されている必要があります-1
(設定されていない場合はデフォルトでデフォルトになるため、他の投稿にそれがあります):.NET docs Push
/の場合Pop
、アクションは/である必要がAdd
ありRemove
、コレクション変更イベントのインデックスは、0
常に操作できる最初のアイテムのみであるというスタックのインデックスである必要があります(thinkstack.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
}
上記のクラスと非常に似ていますが、いくつかの例外があります。
- カウントのコレクション変更のために変更された公開プロップ
- カウントに影響を与える可能性のある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;
}
}