Silakan merujuk ke versi C # 7 yang diperbarui dan dioptimalkan . Saya tidak ingin menghapus versi VB.NET jadi saya hanya mempostingnya di jawaban yang terpisah.
Tampaknya tidak didukung, saya menerapkannya sendiri, FYI, semoga bermanfaat:
Saya memperbarui versi VB dan mulai sekarang memunculkan peristiwa sebelum mengubah koleksi sehingga Anda dapat menyesal (berguna saat menggunakan dengan DataGrid
, ListView
dan banyak lagi, bahwa Anda dapat menampilkan konfirmasi "Apakah Anda yakin" kepada pengguna), VB yang diperbarui versi ada di bagian bawah pesan ini .
Terima permintaan maaf saya bahwa layar terlalu sempit untuk memuat kode saya, saya juga tidak suka.
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) { }
}
Pembaruan - Koleksi rentang yang dapat diobservasi dengan pemberitahuan perubahan koleksi
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");
danOnPropertyChanged("Item[]");
menambahkan / menghapus / mengganti berbagai metode untuk sepenuhnya meniru standar ObservableCollection.Pertama-tama, silakan suara dan komentar pada permintaan API di NET repo.
Berikut versi saya dioptimalkan dari
ObservableRangeCollection
(versi yang dioptimalkan dari James Montemagno ini satu ).Kerjanya sangat cepat dan dimaksudkan untuk menggunakan kembali elemen yang ada bila memungkinkan dan menghindari peristiwa yang tidak perlu, atau mengelompokkannya menjadi satu, jika memungkinkan. Itu
ReplaceRange
Metode Menggantikan / Menghapus / menambah elemen yang dibutuhkan oleh indeks yang tepat dan batch peristiwa mungkin.Diuji pada Xamarin. UI UI dengan hasil yang bagus untuk pembaruan yang sangat sering ke koleksi besar (5-7 pembaruan per detik).
Catatan: Karena WPF tidak terbiasa bekerja dengan operasi rentang, ia akan membuang a
NotSupportedException
, ketika menggunakanObservableRangeCollection
dari bawah ini dalam pekerjaan terkait WPF UI, seperti mengikatnya keListBox
dll. (Anda masih dapat menggunakanObservableRangeCollection<T>
jika tidak terikat ke UI) .Namun Anda dapat menggunakan
WpfObservableRangeCollection<T>
solusinya.Solusi nyata akan menciptakan
CollectionView
yang tahu bagaimana menangani berbagai operasi, tetapi saya masih tidak punya waktu untuk mengimplementasikannya.Kode RAW - buka sebagai Raw, lalu lakukanCtrl+Auntuk memilih semua, laluCtrl+Cuntuk menyalin.
sumber
Saya pikir AddRange lebih baik diimplementasikan seperti:
Ini menghemat salinan daftar. Juga jika Anda ingin mengoptimalkan mikro, Anda bisa menambahkan hingga N item dan jika lebih dari N item yang ditambahkan lakukan reset.
sumber
Anda harus berhati-hati mengikat UI ke koleksi khusus Anda - kelas Default CollectionView hanya mendukung satu pemberitahuan item.
sumber
Bukti kebutuhan
OnPropertyChanged("Count")
danOnPropertyChanged("Item[]")
panggilan untuk berperilaku sesuaiObservableCollection
. Perhatikan bahwa saya tidak tahu apa konsekuensinya jika Anda tidak repot-repot!Berikut adalah metode pengujian yang menunjukkan bahwa ada dua peristiwa PropertyChange untuk setiap penambahan dalam koleksi yang bisa diamati secara normal. Satu untuk
"Count"
dan satu untuk"Item[]"
.@ Kimmy, tukar standar untuk koleksi Anda dan ubah ke rentang tambah dan Anda akan mendapatkan nol Perubahan Properti. Perhatikan bahwa perubahan koleksi tidak berfungsi dengan baik, tetapi tidak melakukan apa yang dilakukan oleh ObservableCollection. Jadi Tes untuk koleksi shimmy terlihat seperti ini:
FYI di sini adalah kode dari InsertItem (juga disebut dengan Add) dari ObservableCollection:
sumber
C # dirangkum keturunan.
Lebih banyak bacaan: http://blogs.msdn.com/b/nathannesbit/archive/2009/04/20/addrange-and-observablecollection.aspx
sumber
Ya, menambahkan Koleksi yang Dapat Diobservasi Anda sendiri akan cukup adil. Jangan lupa untuk membuat acara yang tepat terlepas dari apakah itu digunakan oleh UI untuk saat ini atau tidak;) Anda harus meningkatkan pemberitahuan perubahan properti untuk properti "Item []" (diperlukan oleh sisi WPF dan kontrol terikat) serta NotifyCollectionChangedEventArgs dengan satu set item yang ditambahkan (rentang Anda). Saya sudah melakukan hal-hal seperti itu (juga menyortir dukungan dan beberapa hal lain) dan tidak punya masalah dengan kedua lapisan Presentation dan Code Behind.
sumber
Karena mungkin ada sejumlah operasi yang harus dilakukan pada ObservableCollection misalnya Hapus pertama kemudian AddRange dan kemudian masukkan "Semua" item untuk ComboBox saya berakhir dengan solusi berikut:
Dan contoh cara menggunakannya:
Reset notifikasi hanya akan dipanggil satu kali setelah Execute selesai memproses daftar yang mendasarinya.
sumber
Berikut ini beberapa bantuan tambahan untuk masalah koleksi yang berubah dan UI:
sumber
ObservableRangeCollection harus lulus tes suka
kalau tidak kita dapatkan
saat menggunakan dengan kontrol.
Saya tidak melihat solusi yang ideal, tetapi NotifyCollectionChangedAction.Reset alih-alih Tambah / Hapus sebagian menyelesaikan masalah. Lihat http://blogs.msdn.com/b/nathannesbit/archive/2009/04/20/addrange-and-observablecollection.aspx seperti yang disebutkan oleh net_prog
sumber
Berikut ini adalah modifikasi dari jawaban yang diterima untuk menyediakan lebih banyak fungsi.
RangeCollection.cs:
Kelas Acara:
Catatan: Saya tidak secara manual meningkatkan
OnCollectionChanged
metode dasar karena tampaknya hanya mungkin untuk membuat tindakanCollectionChangedEventArgs
menggunakanReset
. Jika Anda mencoba meningkatkanOnCollectionChanged
penggunaanReset
untuk perubahan item tunggal, kontrol item Anda akan tampak berkedip, yang merupakan sesuatu yang ingin Anda hindari.sumber
Anda juga dapat menggunakan kode ini untuk memperluas ObservableCollection:
Maka Anda tidak perlu mengubah kelas dalam kode yang ada.
sumber