Bitte beziehen Sie sich auf die aktualisierte und optimierte C # 7-Version . Ich wollte die VB.NET-Version nicht entfernen, deshalb habe ich sie nur in einer separaten Antwort veröffentlicht.
Scheint, dass es nicht unterstützt wird, ich habe es selbst implementiert, FYI, hoffe es ist hilfreich:
Ich die VB - Version aktualisiert und von nun an ein Ereignis auslöst , bevor die Sammlung zu ändern , so können Sie bedauern (nützlich , wenn bei der Verwendung DataGrid
, ListView
und viele mehr, dass Sie zeigen eine „Sind Sie sicher , dass“ eine Bestätigung für den Benutzer), die aktualisierten VB Die Version befindet sich am Ende dieser Nachricht .
Bitte akzeptieren Sie meine Entschuldigung, dass der Bildschirm zu eng ist, um meinen Code zu enthalten. Ich mag ihn auch nicht.
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) { }
}
Update - Beobachtbare Bereichssammlung mit Benachrichtigung über Sammlungsänderungen
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
OnPropertyChanged("Count");
undOnPropertyChanged("Item[]");
in der Hinzufügen / Entfernen / Bereich Methoden ersetzen , um den Standard ObservableCollection vollständig mimik.Bitte stimmen Sie zunächst ab und kommentieren Sie die API-Anfrage im .NET-Repo.
Hier ist meine optimierte Version des
ObservableRangeCollection
(optimierte Version von James Montemagno ist ein ).Es arbeitet sehr schnell und soll vorhandene Elemente nach Möglichkeit wiederverwenden und unnötige Ereignisse vermeiden oder wenn möglich zu einem zusammenfassen. Das
ReplaceRange
Methode ersetzt / entfernt / fügt die erforderlichen Elemente durch die entsprechenden Indizes hinzu und stapelt die möglichen Ereignisse.Getestet auf der Xamarin.Forms-Benutzeroberfläche mit hervorragenden Ergebnissen für sehr häufige Aktualisierungen der großen Sammlung (5-7 Aktualisierungen pro Sekunde).
Hinweis: Da WPF nicht daran gewöhnt ist, mit Bereichsoperationen zu arbeiten, wird
NotSupportedException
bei Verwendung derObservableRangeCollection
von unten in WPF-UI-bezogenen Arbeit, z. B. beim Binden an eineListBox
usw. , ein a ausgelöst (Sie können die,ObservableRangeCollection<T>
wenn nicht an die UI gebunden, weiterhin verwenden ). .Sie können jedoch die
WpfObservableRangeCollection<T>
Problemumgehung verwenden.Die wirkliche Lösung wäre die Schaffung eines
CollectionView
, der weiß, wie man mit Bereichsoperationen umgeht, aber ich hatte immer noch nicht die Zeit, dies zu implementieren.RAW-Code - als Raw öffnen, dannCtrl+Aalle auswählen und dannCtrl+Ckopieren.
quelle
Ich denke, AddRange ist besser so implementiert:
Es speichert Ihnen eine Listenkopie. Wenn Sie eine Mikrooptimierung durchführen möchten, können Sie auch bis zu N Elemente hinzufügen. Wenn mehr als N Elemente hinzugefügt wurden, führen Sie einen Reset durch.
quelle
Sie müssen die Benutzeroberfläche sorgfältig an Ihre benutzerdefinierte Sammlung binden. Die Standardklasse CollectionView unterstützt nur die einmalige Benachrichtigung von Elementen.
quelle
Bedarfsnachweis
OnPropertyChanged("Count")
undOnPropertyChanged("Item[]")
Anrufe, um sich wie folgt zu verhaltenObservableCollection
. Beachten Sie, dass ich nicht weiß, was die Konsequenzen sind, wenn Sie sich nicht darum kümmern!Hier ist eine Testmethode, die zeigt, dass es zwei PropertyChange-Ereignisse für jedes Hinzufügen in einer normalen beobachtbaren Sammlung gibt. Eins für
"Count"
und eins für"Item[]"
.@Shimmy, tauschen Sie den Standard für Ihre Sammlung aus und wechseln Sie in einen Add-Bereich. Sie erhalten dann keine PropertyChanges. Beachten Sie, dass die Änderung der Sammlung gut funktioniert, aber nicht genau das tut, was ObservableCollection tut. Der Test für die Shimmy-Sammlung sieht also folgendermaßen aus:
Zu Ihrer Information: Hier ist Code von InsertItem (auch von Add aufgerufen) von ObservableCollection:
quelle
Das C # fasst den Nachkommen zusammen.
Lesen Sie mehr: http://blogs.msdn.com/b/nathannesbit/archive/2009/04/20/addrange-and-observablecollection.aspx
quelle
Ja, das Hinzufügen einer eigenen benutzerdefinierten beobachtbaren Sammlung wäre fair genug. Vergessen Sie nicht, entsprechende Ereignisse auszulösen, unabhängig davon, ob sie momentan von der Benutzeroberfläche verwendet werden oder nicht;) Sie müssen die Benachrichtigung über Eigenschaftsänderungen für die Eigenschaft "Item []" (erforderlich für WPF-seitige und gebundene Steuerelemente) sowie für NotifyCollectionChangedEventArgs auslösen mit einer Reihe von Elementen hinzugefügt (Ihr Bereich). Ich habe solche Dinge getan (sowie Sortierunterstützung und einige andere Dinge) und hatte keine Probleme mit den Ebenen "Präsentation" und "Code Behind".
quelle
Da eine ObservableCollection möglicherweise eine Reihe von Vorgängen ausführen muss, z. B. zuerst löschen, dann AddRange hinzufügen und dann das Element "Alle" für eine ComboBox einfügen, ergab sich folgende Lösung:
Und Beispiel, wie man es benutzt:
Die Reset-Benachrichtigung wird nur einmal aufgerufen, nachdem Execute die Verarbeitung der zugrunde liegenden Liste abgeschlossen hat.
quelle
Hier ist eine zusätzliche Hilfe für geänderte Sammlungs- und Benutzeroberflächenprobleme:
quelle
ObservableRangeCollection sollte einen Test wie bestehen
sonst bekommen wir
während der Verwendung mit einem Steuerelement.
Ich sehe keine ideale Lösung, aber NotifyCollectionChangedAction.Reset anstelle von Hinzufügen / Entfernen löst das Problem teilweise. Siehe http://blogs.msdn.com/b/nathannesbit/archive/2009/04/20/addrange-and-observablecollection.aspx, wie von net_prog erwähnt
quelle
Hier ist eine Änderung der akzeptierten Antwort, um mehr Funktionalität bereitzustellen.
RangeCollection.cs:
Veranstaltungsklassen:
Hinweis: Ich habe
OnCollectionChanged
die Basismethoden nicht manuell ausgelöst , da es anscheinend nur möglich ist,CollectionChangedEventArgs
mithilfe derReset
Aktion eine zu erstellen . Wenn Sie versuchen,OnCollectionChanged
mitReset
für eine einzelne Elementänderung zu erhöhen , scheint Ihr Elementsteuerelement zu flackern, was Sie vermeiden möchten.quelle
Sie können diesen Code auch verwenden, um ObservableCollection zu erweitern:
Dann müssen Sie die Klasse im vorhandenen Code nicht ändern.
quelle