36

System.Collections.ObjectModel ObservableCollection<T>クラスを検討していました。これは奇妙だから

  • 1 つの項目のみを受け取る Add メソッドがあります。AddRange または同等のものはありません。
  • Notification イベントの引数には NewItems プロパティがあり、これは(オブジェクトの.. T ではなく) IListです。

ここで必要なのは、オブジェクトのバッチをコレクションに追加することであり、リスナーも通知の一部としてバッチを取得します。ObservableCollection で何か不足していますか? 私の仕様を満たす別のクラスはありますか?

更新: 可能な限り自分でロールバックしたくありません。追加/削除/変更などを組み込む必要があります。たくさんのものがあります。


関連する質問:
https://stackoverflow.com/questions/670577/observablecollection-doesnt-support-addrange-method-so-i-get-notified-for-each

4

10 に答える 10

20

INotifyCollectionChanged複数のアイテムが追加されたときにインターフェイスが更新できるように見えるのでObservableCollection<T>AddRange. の拡張メソッドを作成できますが、AddRange追加されるすべてのアイテムに対してイベントが発生します。ObservableCollection<T>それが受け入れられない場合は、次のように継承できるはずです。

public class MyObservableCollection<T> : ObservableCollection<T>
{
    // matching constructors ...

    bool isInAddRange = false;

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        // intercept this when it gets called inside the AddRange method.
        if (!isInAddRange) 
            base.OnCollectionChanged(e);
    }


    public void AddRange(IEnumerable<T> items)
    {
         isInAddRange = true;
         foreach (T item in items)
            Add(item);
         isInAddRange = false;

         var e = new NotifyCollectionChangedEventArgs(
             NotifyCollectionChangedAction.Add,
             items.ToList());
         base.OnCollectionChanged(e);
    }
}
于 2008-09-11T16:43:52.413 に答える
6

アイデアは flyguybob のアイデアと同じです。このことのイベント引数はジェネリックを使用しません.. IList を使用させます (そうです.. 昨日 :) テスト済みのスニペットは次のとおりです...

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;

namespace MyNamespace
{
    public class ObservableCollectionWithBatchUpdates<T> : ObservableCollection<T>
    {
        public void AddRange(ICollection<T> obNewItems)
        {
            IList<T> obAddedItems = new List<T>();
            foreach (T obItem in obNewItems)
            {
                Items.Add(obItem);
                obAddedItems.Add(obItem);
            }
            NotifyCollectionChangedEventArgs obEvtArgs = new NotifyCollectionChangedEventArgs(
               NotifyCollectionChangedAction.Add, 
               obAddedItems as System.Collections.IList);
            base.OnCollectionChanged(obEvtArgs);
        }

    }
}
于 2008-09-14T19:03:47.557 に答える
4

add rangeコマンドを送信し、observablecolletionをリストビューにバインドする上記の実装のいずれかを使用すると、この厄介なエラーが発生します。

NotSupportedException
   System.Windows.Data.ListCollectionView.ValidateCollectionChangedEventArgs(NotifyCollectionChangedEventArgs e)で
   System.Windows.Data.ListCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs args)で
   System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(オブジェクト送信者、NotifyCollectionChangedEventArgs e)で
   System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs e)で

私が行った実装では、WPFフレームワークの周囲でより均等に実装されているResetイベントを使用しています。

    public void AddRange(IEnumerable<T> collection)
    {
        foreach (var i in collection) Items.Add(i);
        OnPropertyChanged("Count");
        OnPropertyChanged("Item[]");
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }
于 2009-05-12T04:54:58.787 に答える
4

良い賭けであるだけでなくSystem.Collections.ObjectModel.Collection<T>、ヘルプ ドキュメントには、通知を受け取るためにさまざまな保護されたメソッドをオーバーライドする方法の例があります。(例 2 まで下にスクロールします。)

于 2008-09-12T03:13:10.293 に答える
3

私はこの種の質問を何度も見てきましたが、Microsoft でさえ ObservableCollection を他の場所で宣伝しているのはなぜでしょうか。

BindingList<T>

これにより、通知をオフにして一括操作を実行してから、通知をオンにすることができます。

于 2010-09-30T09:58:37.800 に答える
2

ある種のコレクションから継承したい場合は、System.Collections.ObjectModel.Collection から継承した方がよいでしょう。オーバーライド用の仮想メソッドが提供されているからです。そのルートに行く場合は、リストからメソッドをシャドウする必要があります。

この機能を提供する組み込みのコレクションは知りませんが、修正されることを歓迎します:)

于 2008-09-11T16:21:44.680 に答える
2

CollectionView パターンに似た別のソリューション:

public class DeferableObservableCollection<T> : ObservableCollection<T>
{
    private int deferLevel;

    private class DeferHelper<T> : IDisposable
    {
        private DeferableObservableCollection<T> owningCollection;
        public DeferHelper(DeferableObservableCollection<T> owningCollection)
        {
            this.owningCollection = owningCollection;
        }

        public void Dispose()
        {
            owningCollection.EndDefer();
        }
    }

    private void EndDefer()
    {
        if (--deferLevel <= 0)
        {
            deferLevel = 0;
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }
    }

    public IDisposable DeferNotifications()
    {
        deferLevel++;
        return new DeferHelper<T>(this);
    }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (deferLevel == 0) // Not in a defer just send events as normally
        {
            base.OnCollectionChanged(e);
        } // Else notify on EndDefer
    }
}
于 2012-01-12T15:30:13.313 に答える
1

List<T> から継承し、Add() メソッドと AddRange() メソッドをオーバーライドしてイベントを発生させますか?

于 2008-09-11T16:19:10.490 に答える
0

C#とVBの両方でAddRange、RemoveRange、Replacerangeメソッドを使用したObservableコレクションを見てください。

VBの場合:INotifyCollectionChangingの実装。

于 2009-07-14T03:25:12.300 に答える
0

すばやく追加するには、次を使用できます。

((List<Person>)this.Items).AddRange(NewItems);
于 2009-11-24T14:30:21.900 に答える