183

範囲を追加して、一括全体を更新できるようにしたいと考えています。

また、アクションが完了する前にアクションをキャンセルできるようにしたいと考えています (つまり、「変更」以外のコレクションの変更)。


関連 Q 一度に複数のオブジェクトを追加して通知を受け取るための .Net コレクションはどれですか?

4

13 に答える 13

133

更新および最適化された C# 7 バージョン を参照してください。VB.NET バージョンを削除したくなかったので、別の回答に投稿しました。

更新されたバージョンに移動

サポートされていないようです。私は自分で実装しました。参考までに、参考になれば幸いです。

私はVBバージョンを更新し、今後はコレクションを変更する前にイベントを発生させるので、後悔することができます( 、およびユーザーに「よろしいですか」の確認を表示できるなど、多くの場合に役立ちDataGridますListView)、更新されたVBバージョンはこのメッセージの下部にあります

画面が狭すぎて私のコードを含めることができないことをお詫びします。私もそれが好きではありません。

VB.NET:

Imports System.Collections.Specialized

Namespace System.Collections.ObjectModel
    ''' <summary>
    ''' Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.
    ''' </summary>
    ''' <typeparam name="T"></typeparam>
    Public Class ObservableRangeCollection(Of T) : Inherits System.Collections.ObjectModel.ObservableCollection(Of T)

        ''' <summary>
        ''' Adds the elements of the specified collection to the end of the ObservableCollection(Of T).
        ''' </summary>
        Public Sub AddRange(ByVal collection As IEnumerable(Of T))
            For Each i In collection
                Items.Add(i)
            Next
            OnCollectionChanged(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))
        End Sub

        ''' <summary>
        ''' Removes the first occurence of each item in the specified collection from ObservableCollection(Of T).
        ''' </summary>
        Public Sub RemoveRange(ByVal collection As IEnumerable(Of T))
            For Each i In collection
                Items.Remove(i)
            Next

            OnCollectionChanged(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))
        End Sub

        ''' <summary>
        ''' Clears the current collection and replaces it with the specified item.
        ''' </summary>
        Public Sub Replace(ByVal item As T)
            ReplaceRange(New T() {item})
        End Sub
        ''' <summary>
        ''' Clears the current collection and replaces it with the specified collection.
        ''' </summary>
        Public Sub ReplaceRange(ByVal collection As IEnumerable(Of T))
            Dim old = Items.ToList
            Items.Clear()
            For Each i In collection
                Items.Add(i)
            Next
            OnCollectionChanged(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))
        End Sub

        ''' <summary>
        ''' Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub New()
            MyBase.New()
        End Sub
        ''' <summary>
        ''' Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class that contains elements copied from the specified collection.
        ''' </summary>
        ''' <param name="collection">collection: The collection from which the elements are copied.</param>
        ''' <exception cref="System.ArgumentNullException">The collection parameter cannot be null.</exception>
        Public Sub New(ByVal collection As IEnumerable(Of T))
            MyBase.New(collection)
        End Sub
    End Class   

End Namespace

C#:

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

/// <summary> 
/// Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed. 
/// </summary> 
/// <typeparam name="T"></typeparam> 
public class ObservableRangeCollection<T> : ObservableCollection<T>
{
    /// <summary> 
    /// Adds the elements of the specified collection to the end of the ObservableCollection(Of T). 
    /// </summary> 
    public void AddRange(IEnumerable<T> collection)
    {
        if (collection == null) throw new ArgumentNullException("collection");

        foreach (var i in collection) Items.Add(i);
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    /// <summary> 
    /// Removes the first occurence of each item in the specified collection from ObservableCollection(Of T). 
    /// </summary> 
    public void RemoveRange(IEnumerable<T> collection)
    {
        if (collection == null) throw new ArgumentNullException("collection");

        foreach (var i in collection) Items.Remove(i);
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    /// <summary> 
    /// Clears the current collection and replaces it with the specified item. 
    /// </summary> 
    public void Replace(T item)
    {
        ReplaceRange(new T[] { item });
    }

    /// <summary> 
    /// Clears the current collection and replaces it with the specified collection. 
    /// </summary> 
    public void ReplaceRange(IEnumerable<T> collection)
    {
        if (collection == null) throw new ArgumentNullException("collection");

        Items.Clear();
        foreach (var i in collection) Items.Add(i);
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    /// <summary> 
    /// Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class. 
    /// </summary> 
    public ObservableRangeCollection()
        : base() { }

    /// <summary> 
    /// Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class that contains elements copied from the specified collection. 
    /// </summary> 
    /// <param name="collection">collection: The collection from which the elements are copied.</param> 
    /// <exception cref="System.ArgumentNullException">The collection parameter cannot be null.</exception> 
    public ObservableRangeCollection(IEnumerable<T> collection)
        : base(collection) { }
}

更新 - コレクション変更通知付きの観測範囲コレクション

Imports System.Collections.Specialized
Imports System.ComponentModel
Imports System.Collections.ObjectModel

Public Class ObservableRangeCollection(Of T) : Inherits ObservableCollection(Of T) : Implements INotifyCollectionChanging(Of T)
    ''' <summary>
    ''' Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class.
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub New()
        MyBase.New()
    End Sub

    ''' <summary>
    ''' Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class that contains elements copied from the specified collection.
    ''' </summary>
    ''' <param name="collection">collection: The collection from which the elements are copied.</param>
    ''' <exception cref="System.ArgumentNullException">The collection parameter cannot be null.</exception>
    Public Sub New(ByVal collection As IEnumerable(Of T))
        MyBase.New(collection)
    End Sub

    ''' <summary>
    ''' Adds the elements of the specified collection to the end of the ObservableCollection(Of T).
    ''' </summary>
    Public Sub AddRange(ByVal collection As IEnumerable(Of T))
        Dim ce As New NotifyCollectionChangingEventArgs(Of T)(NotifyCollectionChangedAction.Add, collection)
        OnCollectionChanging(ce)
        If ce.Cancel Then Exit Sub

        Dim index = Items.Count - 1
        For Each i In collection
            Items.Add(i)
        Next

        OnCollectionChanged(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, collection, index))
    End Sub


    ''' <summary>
    ''' Inserts the collection at specified index.
    ''' </summary>
    Public Sub InsertRange(ByVal index As Integer, ByVal Collection As IEnumerable(Of T))
        Dim ce As New NotifyCollectionChangingEventArgs(Of T)(NotifyCollectionChangedAction.Add, Collection)
        OnCollectionChanging(ce)
        If ce.Cancel Then Exit Sub

        For Each i In Collection
            Items.Insert(index, i)
        Next

        OnCollectionChanged(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))
    End Sub


    ''' <summary>
    ''' Removes the first occurence of each item in the specified collection from ObservableCollection(Of T).
    ''' </summary>
    Public Sub RemoveRange(ByVal collection As IEnumerable(Of T))
        Dim ce As New NotifyCollectionChangingEventArgs(Of T)(NotifyCollectionChangedAction.Remove, collection)
        OnCollectionChanging(ce)
        If ce.Cancel Then Exit Sub

        For Each i In collection
            Items.Remove(i)
        Next

        OnCollectionChanged(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))
    End Sub



    ''' <summary>
    ''' Clears the current collection and replaces it with the specified item.
    ''' </summary>
    Public Sub Replace(ByVal item As T)
        ReplaceRange(New T() {item})
    End Sub

    ''' <summary>
    ''' Clears the current collection and replaces it with the specified collection.
    ''' </summary>
    Public Sub ReplaceRange(ByVal collection As IEnumerable(Of T))
        Dim ce As New NotifyCollectionChangingEventArgs(Of T)(NotifyCollectionChangedAction.Replace, Items)
        OnCollectionChanging(ce)
        If ce.Cancel Then Exit Sub

        Items.Clear()
        For Each i In collection
            Items.Add(i)
        Next
        OnCollectionChanged(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))
    End Sub

    Protected Overrides Sub ClearItems()
        Dim e As New NotifyCollectionChangingEventArgs(Of T)(NotifyCollectionChangedAction.Reset, Items)
        OnCollectionChanging(e)

        If e.Cancel Then Exit Sub

        MyBase.ClearItems()
    End Sub

    Protected Overrides Sub InsertItem(ByVal index As Integer, ByVal item As T)
        Dim ce As New NotifyCollectionChangingEventArgs(Of T)(NotifyCollectionChangedAction.Add, item)
        OnCollectionChanging(ce)
        If ce.Cancel Then Exit Sub

        MyBase.InsertItem(index, item)
    End Sub

    Protected Overrides Sub MoveItem(ByVal oldIndex As Integer, ByVal newIndex As Integer)
        Dim ce As New NotifyCollectionChangingEventArgs(Of T)()
        OnCollectionChanging(ce)
        If ce.Cancel Then Exit Sub

        MyBase.MoveItem(oldIndex, newIndex)
    End Sub

    Protected Overrides Sub RemoveItem(ByVal index As Integer)
        Dim ce As New NotifyCollectionChangingEventArgs(Of T)(NotifyCollectionChangedAction.Remove, Items(index))
        OnCollectionChanging(ce)
        If ce.Cancel Then Exit Sub

        MyBase.RemoveItem(index)
    End Sub

    Protected Overrides Sub SetItem(ByVal index As Integer, ByVal item As T)
        Dim ce As New NotifyCollectionChangingEventArgs(Of T)(NotifyCollectionChangedAction.Replace, Items(index))
        OnCollectionChanging(ce)
        If ce.Cancel Then Exit Sub

        MyBase.SetItem(index, item)
    End Sub

    Protected Overrides Sub OnCollectionChanged(ByVal e As Specialized.NotifyCollectionChangedEventArgs)
        If e.NewItems IsNot Nothing Then
            For Each i As T In e.NewItems
                If TypeOf i Is INotifyPropertyChanged Then AddHandler DirectCast(i, INotifyPropertyChanged).PropertyChanged, AddressOf Item_PropertyChanged
            Next
        End If
        MyBase.OnCollectionChanged(e)
    End Sub

    Private Sub Item_PropertyChanged(ByVal sender As T, ByVal e As ComponentModel.PropertyChangedEventArgs)
        OnCollectionChanged(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset, sender, IndexOf(sender)))
    End Sub

    Public Event CollectionChanging(ByVal sender As Object, ByVal e As NotifyCollectionChangingEventArgs(Of T)) Implements INotifyCollectionChanging(Of T).CollectionChanging
    Protected Overridable Sub OnCollectionChanging(ByVal e As NotifyCollectionChangingEventArgs(Of T))
        RaiseEvent CollectionChanging(Me, e)
    End Sub
End Class


Public Interface INotifyCollectionChanging(Of T)
    Event CollectionChanging(ByVal sender As Object, ByVal e As NotifyCollectionChangingEventArgs(Of T))
End Interface

Public Class NotifyCollectionChangingEventArgs(Of T) : Inherits CancelEventArgs

    Public Sub New()
        m_Action = NotifyCollectionChangedAction.Move
        m_Items = New T() {}
    End Sub

    Public Sub New(ByVal action As NotifyCollectionChangedAction, ByVal item As T)
        m_Action = action
        m_Items = New T() {item}
    End Sub

    Public Sub New(ByVal action As NotifyCollectionChangedAction, ByVal items As IEnumerable(Of T))
        m_Action = action
        m_Items = items
    End Sub

    Private m_Action As NotifyCollectionChangedAction
    Public ReadOnly Property Action() As NotifyCollectionChangedAction
        Get
            Return m_Action
        End Get
    End Property

    Private m_Items As IList
    Public ReadOnly Property Items() As IEnumerable(Of T)
        Get
            Return m_Items
        End Get
    End Property
End Class
于 2009-03-22T05:09:55.490 に答える
33

AddRange は次のように実装したほうがよいと思います。

public void AddRange(IEnumerable<T> collection)
{
    foreach (var i in collection) Items.Add(i);
    OnCollectionChanged(
        new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}

リストのコピーが保存されます。また、マイクロ最適化したい場合は、最大 N 個のアイテムを追加し、追加されたアイテムが N 個を超える場合はリセットを実行できます。

于 2009-05-12T04:26:27.287 に答える
14

カスタム コレクションへの UI のバインドには注意が必要です。デフォルトの CollectionView クラスは、アイテムの単一の通知のみをサポートします。

于 2009-03-22T10:08:08.110 に答える
13

に従って動作するためのOnPropertyChanged("Count")との呼び出しの必要性の証明。あなたが気にしなければ、結果がどうなるかわからないことに注意してください!OnPropertyChanged("Item[]")ObservableCollection

これは、通常の監視可能なコレクションの追加ごとに 2 つの PropertyChange イベントがあることを示すテスト メソッドです。の 1"Count"つと の 1 つ"Item[]"

[TestMethod]
public void TestAddSinglesInOldObsevableCollection()
{
  int colChangedEvents = 0;
  int propChangedEvents = 0;
  var collection = new ObservableCollection<object>();
  collection.CollectionChanged += (sender, e) => { colChangedEvents++; };
  (collection as INotifyPropertyChanged).PropertyChanged += (sender, e) => { propChangedEvents++; };
  collection.Add(new object());
  collection.Add(new object());
  collection.Add(new object());
  Assert.AreEqual(3, colChangedEvents);
  Assert.AreEqual(6, propChangedEvents);
}

@Shimmy 、コレクションの標準を交換し、追加範囲に変更すると、 PropertyChanges がゼロになります。コレクションの変更は正常に機能しますが、ObservableCollection が行うこととまったく同じではないことに注意してください。したがって、shimmy コレクションのテストは次のようになります。

[TestMethod]
public void TestShimmyAddRange()
{
  int colChangedEvents = 0;
  int propChangedEvents = 0;
  var collection = new ShimmyObservableCollection<object>();
  collection.CollectionChanged += (sender, e) => { colChangedEvents++; };
  (collection as INotifyPropertyChanged).PropertyChanged += (sender, e) => { propChangedEvents++; };
  collection.AddRange(new[]{
    new object(), new object(), new object(), new object()}); //4 objects at once
  Assert.AreEqual(1, colChangedEvents);  //great, just one!
  Assert.AreEqual(2, propChangedEvents); //fails, no events :(
}

参考までに、ObservableCollection の InsertItem (Add によっても呼び出される) のコードを次に示します。

protected override void InsertItem(int index, T item)
{
  base.CheckReentrancy();
  base.InsertItem(index, item);
  base.OnPropertyChanged("Count");
  base.OnPropertyChanged("Item[]");
  base.OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index);
}
于 2011-12-08T17:09:20.367 に答える
3

C# の要約された子孫。

詳細: http://blogs.msdn.com/b/nathannesbit/archive/2009/04/20/addrange-and-observablecollection.aspx

public sealed class ObservableCollectionEx<T> : ObservableCollection<T>
{
    #region Ctor

    public ObservableCollectionEx()
    {
    }

    public ObservableCollectionEx(List<T> list) : base(list)
    {
    }

    public ObservableCollectionEx(IEnumerable<T> collection) : base(collection)
    {
    }

    #endregion

    /// <summary> 
    /// Adds the elements of the specified collection to the end of the ObservableCollection(Of T). 
    /// </summary> 
    public void AddRange(
        IEnumerable<T> itemsToAdd,
        ECollectionChangeNotificationMode notificationMode = ECollectionChangeNotificationMode.Add)
    {
        if (itemsToAdd == null)
        {
            throw new ArgumentNullException("itemsToAdd");
        }
        CheckReentrancy();

        if (notificationMode == ECollectionChangeNotificationMode.Reset)
        {
            foreach (var i in itemsToAdd)
            {
                Items.Add(i);
            }

            OnPropertyChanged(new PropertyChangedEventArgs("Count"));
            OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));

            return;
        }

        int startIndex = Count;
        var changedItems = itemsToAdd is List<T> ? (List<T>) itemsToAdd : new List<T>(itemsToAdd);
        foreach (var i in changedItems)
        {
            Items.Add(i);
        }

        OnPropertyChanged(new PropertyChangedEventArgs("Count"));
        OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, changedItems, startIndex));
    }

    public enum ECollectionChangeNotificationMode
    {
        /// <summary>
        /// Notifies that only a portion of data was changed and supplies the changed items (not supported by some elements,
        /// like CollectionView class).
        /// </summary>
        Add,

        /// <summary>
        /// Notifies that the entire collection was changed, does not supply the changed items (may be inneficient with large
        /// collections as requires the full update even if a small portion of items was added).
        /// </summary>
        Reset
    }
}
于 2015-05-12T14:18:13.840 に答える
3

ObservableCollection に対して実行する操作がいくつかある可能性があるため、最初にクリアしてから AddRange を実行し、次に ComboBox の「すべて」のアイテムを挿入するなど、次のソリューションで終了しました。

public static class LinqExtensions
{
    public static ICollection<T> AddRange<T>(this ICollection<T> source, IEnumerable<T> addSource)
    {
        foreach(T item in addSource)
        {
            source.Add(item);
        }

        return source;
    }
}

public class ExtendedObservableCollection<T>: ObservableCollection<T>
{
    public void Execute(Action<IList<T>> itemsAction)
    {
        itemsAction(Items);
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }
}

そして、それを使用する方法の例:

MyDogs.Execute(items =>
{
    items.Clear();
    items.AddRange(Context.Dogs);
    items.Insert(0, new Dog { Id = 0, Name = "All Dogs" });
});

Reset 通知は、Execute が基になるリストの処理を終了した後に 1 回だけ呼び出されます。

于 2013-11-27T11:10:21.227 に答える
2

はい、独自の Custom Observable Collection を追加するだけで十分です。現時点で UI によって使用されているかどうかに関係なく、適切なイベントを発生させることを忘れないでください;) NotifyCollectionChangedEventArgs だけでなく、"Item[]" プロパティ (WPF 側およびバインドされたコントロールで必要) のプロパティ変更通知を発生させる必要があります。一連のアイテムが追加されています(範囲)。私はそのようなことを行いました(ソートのサポートやその他のことも)、プレゼンテーション層と分離コード層の両方で問題はありませんでした。

于 2009-03-23T08:35:54.173 に答える
1

コレクションの変更と UI の問題に関する追加のヘルプを次に示します。

于 2010-12-17T08:49:07.843 に答える
1

ObservableRangeCollection は次のようなテストに合格する必要があります

[Test]
public void TestAddRangeWhileBoundToListCollectionView()
{
    int collectionChangedEventsCounter = 0;
    int propertyChangedEventsCounter = 0;
    var collection = new ObservableRangeCollection<object>();

    collection.CollectionChanged += (sender, e) => { collectionChangedEventsCounter++; };
    (collection as INotifyPropertyChanged).PropertyChanged += (sender, e) => { propertyChangedEventsCounter++; };

    var list = new ListCollectionView(collection);

    collection.AddRange(new[] { new object(), new object(), new object(), new object() });

    Assert.AreEqual(4, collection.Count);
    Assert.AreEqual(1, collectionChangedEventsCounter);
    Assert.AreEqual(2, propertyChangedEventsCounter);
}

そうでなければ、私たちは得る

System.NotSupportedException : Range actions are not supported.

コントロールで使用中。

理想的な解決策はわかりませんが、追加/削除の代わりに NotifyCollectionChangedAction.Reset を使用すると、問題が部分的に解決されます。net_progで言及されているように、http://blogs.msdn.com/b/nathannesbit/archive/2009/04/20/addrange-and-observablecollection.aspx を参照してください。

于 2015-06-16T11:10:00.150 に答える
0

これは、受け入れられた回答を変更して、より多くの機能を提供するものです。

範囲コレクション.cs:

public class RangeCollection<T> : ObservableCollection<T>
{
    #region Members

    /// <summary>
    /// Occurs when a single item is added.
    /// </summary>
    public event EventHandler<ItemAddedEventArgs<T>> ItemAdded;

    /// <summary>
    /// Occurs when a single item is inserted.
    /// </summary>
    public event EventHandler<ItemInsertedEventArgs<T>> ItemInserted;

    /// <summary>
    /// Occurs when a single item is removed.
    /// </summary>
    public event EventHandler<ItemRemovedEventArgs<T>> ItemRemoved;

    /// <summary>
    /// Occurs when a single item is replaced.
    /// </summary>
    public event EventHandler<ItemReplacedEventArgs<T>> ItemReplaced;

    /// <summary>
    /// Occurs when items are added to this.
    /// </summary>
    public event EventHandler<ItemsAddedEventArgs<T>> ItemsAdded;

    /// <summary>
    /// Occurs when items are removed from this.
    /// </summary>
    public event EventHandler<ItemsRemovedEventArgs<T>> ItemsRemoved;

    /// <summary>
    /// Occurs when items are replaced within this.
    /// </summary>
    public event EventHandler<ItemsReplacedEventArgs<T>> ItemsReplaced;

    /// <summary>
    /// Occurs when entire collection is cleared.
    /// </summary>
    public event EventHandler<ItemsClearedEventArgs<T>> ItemsCleared;

    /// <summary>
    /// Occurs when entire collection is replaced.
    /// </summary>
    public event EventHandler<CollectionReplacedEventArgs<T>> CollectionReplaced;

    #endregion

    #region Helper Methods

    /// <summary>
    /// Throws exception if any of the specified objects are null.
    /// </summary>
    private void Check(params T[] Items)
    {
        foreach (T Item in Items)
        {
            if (Item == null)
            {
                throw new ArgumentNullException("Item cannot be null.");
            }
        }
    }

    private void Check(IEnumerable<T> Items)
    {
        if (Items == null) throw new ArgumentNullException("Items cannot be null.");
    }

    private void Check(IEnumerable<IEnumerable<T>> Items)
    {
        if (Items == null) throw new ArgumentNullException("Items cannot be null.");
    }

    private void RaiseChanged(NotifyCollectionChangedAction Action)
    {
        this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
        this.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
        this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    #endregion

    #region Bulk Methods

    /// <summary> 
    /// Adds the elements of the specified collection to the end of this.
    /// </summary> 
    public void AddRange(IEnumerable<T> NewItems)
    {
        this.Check(NewItems);
        foreach (var i in NewItems) this.Items.Add(i);
        this.RaiseChanged(NotifyCollectionChangedAction.Reset);
        this.OnItemsAdded(new ItemsAddedEventArgs<T>(NewItems));
    }

    /// <summary>
    /// Adds variable IEnumerable<T> to this.
    /// </summary>
    /// <param name="List"></param>
    public void AddRange(params IEnumerable<T>[] NewItems)
    {
        this.Check(NewItems);
        foreach (IEnumerable<T> Items in NewItems) foreach (T Item in Items) this.Items.Add(Item);
        this.RaiseChanged(NotifyCollectionChangedAction.Reset);
        //TO-DO: Raise OnItemsAdded with combined IEnumerable<T>.
    }

    /// <summary> 
    /// Removes the first occurence of each item in the specified collection. 
    /// </summary> 
    public void Remove(IEnumerable<T> OldItems)
    {
        this.Check(OldItems);
        foreach (var i in OldItems) Items.Remove(i);
        this.RaiseChanged(NotifyCollectionChangedAction.Reset);
        OnItemsRemoved(new ItemsRemovedEventArgs<T>(OldItems));
    }

    /// <summary>
    /// Removes all occurences of each item in the specified collection.
    /// </summary>
    /// <param name="itemsToRemove"></param>
    public void RemoveAll(IEnumerable<T> OldItems)
    {
        this.Check(OldItems);
        var set = new HashSet<T>(OldItems);
        var list = this as List<T>;
        int i = 0;
        while (i < this.Count) if (set.Contains(this[i])) this.RemoveAt(i); else i++;
        this.RaiseChanged(NotifyCollectionChangedAction.Reset);
        OnItemsRemoved(new ItemsRemovedEventArgs<T>(OldItems));
    }

    /// <summary> 
    /// Replaces all occurences of a single item with specified item.
    /// </summary> 
    public void ReplaceAll(T Old, T New)
    {
        this.Check(Old, New);
        this.Replace(Old, New, false);
        this.RaiseChanged(NotifyCollectionChangedAction.Reset);
        this.OnItemReplaced(new ItemReplacedEventArgs<T>(Old, New));
    }

    /// <summary> 
    /// Clears this and adds specified collection. 
    /// </summary> 
    public void ReplaceCollection(IEnumerable<T> NewItems, bool SupressEvent = false)
    {
        this.Check(NewItems);
        IEnumerable<T> OldItems = new List<T>(this.Items);
        this.Items.Clear();
        foreach (T Item in NewItems) this.Items.Add(Item);
        this.RaiseChanged(NotifyCollectionChangedAction.Reset);
        this.OnReplaced(new CollectionReplacedEventArgs<T>(OldItems, NewItems));
    }

    private void Replace(T Old, T New, bool BreakFirst)
    {
        List<T> Cloned = new List<T>(this.Items);
        int i = 0;
        foreach (T Item in Cloned)
        {
            if (Item.Equals(Old))
            {
                this.Items.Remove(Item);
                this.Items.Insert(i, New);
                if (BreakFirst) break;
            }
            i++;
        }
    }

    /// <summary> 
    /// Replaces the first occurence of a single item with specified item.
    /// </summary> 
    public void Replace(T Old, T New)
    {
        this.Check(Old, New);
        this.Replace(Old, New, true);
        this.RaiseChanged(NotifyCollectionChangedAction.Reset);
        this.OnItemReplaced(new ItemReplacedEventArgs<T>(Old, New));
    }

    #endregion

    #region  New Methods

    /// <summary>
    /// Removes a single item.
    /// </summary>
    /// <param name="Item"></param>
    public new void Remove(T Item)
    {
        this.Check(Item);
        base.Remove(Item);
        OnItemRemoved(new ItemRemovedEventArgs<T>(Item));
    }

    /// <summary>
    /// Removes a single item at specified index.
    /// </summary>
    /// <param name="i"></param>
    public new void RemoveAt(int i)
    {
        T OldItem = this.Items[i]; //This will throw first if null
        base.RemoveAt(i);
        OnItemRemoved(new ItemRemovedEventArgs<T>(OldItem));
    }

    /// <summary>
    /// Clears this.
    /// </summary>
    public new void Clear()
    {
        IEnumerable<T> OldItems = new List<T>(this.Items);
        this.Items.Clear();
        this.RaiseChanged(NotifyCollectionChangedAction.Reset);
        this.OnCleared(new ItemsClearedEventArgs<T>(OldItems));
    }

    /// <summary>
    /// Adds a single item to end of this.
    /// </summary>
    /// <param name="t"></param>
    public new void Add(T Item)
    {
        this.Check(Item);
        base.Add(Item);
        this.OnItemAdded(new ItemAddedEventArgs<T>(Item));
    }

    /// <summary>
    /// Inserts a single item at specified index.
    /// </summary>
    /// <param name="i"></param>
    /// <param name="t"></param>
    public new void Insert(int i, T Item)
    {
        this.Check(Item);
        base.Insert(i, Item);
        this.OnItemInserted(new ItemInsertedEventArgs<T>(Item, i));
    }

    /// <summary>
    /// Returns list of T.ToString().
    /// </summary>
    /// <returns></returns>
    public new IEnumerable<string> ToString()
    {
        foreach (T Item in this) yield return Item.ToString();
    }

    #endregion

    #region Event Methods

    private void OnItemAdded(ItemAddedEventArgs<T> i)
    {
        if (this.ItemAdded != null) this.ItemAdded(this, new ItemAddedEventArgs<T>(i.NewItem));
    }

    private void OnItemInserted(ItemInsertedEventArgs<T> i)
    {
        if (this.ItemInserted != null) this.ItemInserted(this, new ItemInsertedEventArgs<T>(i.NewItem, i.Index));
    }

    private void OnItemRemoved(ItemRemovedEventArgs<T> i)
    {
        if (this.ItemRemoved != null) this.ItemRemoved(this, new ItemRemovedEventArgs<T>(i.OldItem));
    }

    private void OnItemReplaced(ItemReplacedEventArgs<T> i)
    {
        if (this.ItemReplaced != null) this.ItemReplaced(this, new ItemReplacedEventArgs<T>(i.OldItem, i.NewItem));
    }

    private void OnItemsAdded(ItemsAddedEventArgs<T> i)
    {
        if (this.ItemsAdded != null) this.ItemsAdded(this, new ItemsAddedEventArgs<T>(i.NewItems));
    }

    private void OnItemsRemoved(ItemsRemovedEventArgs<T> i)
    {
        if (this.ItemsRemoved != null) this.ItemsRemoved(this, new ItemsRemovedEventArgs<T>(i.OldItems));
    }

    private void OnItemsReplaced(ItemsReplacedEventArgs<T> i)
    {
        if (this.ItemsReplaced != null) this.ItemsReplaced(this, new ItemsReplacedEventArgs<T>(i.OldItems, i.NewItems));
    }

    private void OnCleared(ItemsClearedEventArgs<T> i)
    {
        if (this.ItemsCleared != null) this.ItemsCleared(this, new ItemsClearedEventArgs<T>(i.OldItems));
    }

    private void OnReplaced(CollectionReplacedEventArgs<T> i)
    {
        if (this.CollectionReplaced != null) this.CollectionReplaced(this, new CollectionReplacedEventArgs<T>(i.OldItems, i.NewItems));
    }

    #endregion

    #region RangeCollection

    /// <summary> 
    /// Initializes a new instance. 
    /// </summary> 
    public RangeCollection() : base() { }

    /// <summary> 
    /// Initializes a new instance from specified enumerable. 
    /// </summary> 
    public RangeCollection(IEnumerable<T> Collection) : base(Collection) { }

    /// <summary> 
    /// Initializes a new instance from specified list.
    /// </summary> 
    public RangeCollection(List<T> List) : base(List) { }

    /// <summary>
    /// Initializes a new instance with variable T.
    /// </summary>
    public RangeCollection(params T[] Items) : base()
    {
        this.AddRange(Items);
    }

    /// <summary>
    /// Initializes a new instance with variable enumerable.
    /// </summary>
    public RangeCollection(params IEnumerable<T>[] Items) : base()
    {
        this.AddRange(Items);
    }

    #endregion
}

イベント クラス:

public class CollectionReplacedEventArgs<T> : ReplacedEventArgs<T>
{
    public CollectionReplacedEventArgs(IEnumerable<T> Old, IEnumerable<T> New) : base(Old, New) { }
}

public class ItemAddedEventArgs<T> : EventArgs
{
    public T NewItem;
    public ItemAddedEventArgs(T t)
    {
        this.NewItem = t;
    }
}

public class ItemInsertedEventArgs<T> : EventArgs
{
    public int Index;
    public T NewItem;
    public ItemInsertedEventArgs(T t, int i)
    {
        this.NewItem = t;
        this.Index = i;
    }
}

public class ItemRemovedEventArgs<T> : EventArgs
{
    public T OldItem;
    public ItemRemovedEventArgs(T t)
    {
        this.OldItem = t;
    }
}

public class ItemReplacedEventArgs<T> : EventArgs
{
    public T OldItem;
    public T NewItem;
    public ItemReplacedEventArgs(T Old, T New)
    {
        this.OldItem = Old;
        this.NewItem = New;
    }
}

public class ItemsAddedEventArgs<T> : EventArgs
{
    public IEnumerable<T> NewItems;
    public ItemsAddedEventArgs(IEnumerable<T> t)
    {
        this.NewItems = t;
    }
}

public class ItemsClearedEventArgs<T> : RemovedEventArgs<T>
{
    public ItemsClearedEventArgs(IEnumerable<T> Old) : base(Old) { }
}

public class ItemsRemovedEventArgs<T> : RemovedEventArgs<T>
{
    public ItemsRemovedEventArgs(IEnumerable<T> Old) : base(Old) { }
}

public class ItemsReplacedEventArgs<T> : ReplacedEventArgs<T>
{
    public ItemsReplacedEventArgs(IEnumerable<T> Old, IEnumerable<T> New) : base(Old, New) { }
}

public class RemovedEventArgs<T> : EventArgs
{
    public IEnumerable<T> OldItems;
    public RemovedEventArgs(IEnumerable<T> Old)
    {
        this.OldItems = Old;
    }
}

public class ReplacedEventArgs<T> : EventArgs
{
    public IEnumerable<T> OldItems;
    public IEnumerable<T> NewItems;
    public ReplacedEventArgs(IEnumerable<T> Old, IEnumerable<T> New)
    {
        this.OldItems = Old;
        this.NewItems = New;
    }
}

注:アクションを使用してOnCollectionChangedを作成することしかできないように見えるため、基本メソッドで手動でレイズしませんでした。単一の項目の変更を使用して上げようとすると、項目コントロールがちらつくように見えますが、これは避けたいことです。CollectionChangedEventArgsResetOnCollectionChangedReset

于 2016-04-13T19:24:22.457 に答える
-1

このコードを使用して、ObservableCollection を拡張することもできます。

public static class ObservableCollectionExtend
{
    public static void AddRange<TSource>(this ObservableCollection<TSource> source, IEnumerable<TSource> items)
    {
        foreach (var item in items)
        {
            source.Add(item);
        }
    }
}

その後、既存のコードでクラスを変更する必要はありません。

于 2012-10-06T17:57:42.417 に答える