Implement AddRange on ObservableCollection with proper DataBinding support
I would like my own descendant to ObservableCollection
support the method AddRange
. Here's what I have now:
public class ObservableCollectionPlus<T> : ObservableCollection<T>
{
public void InsertRange(IEnumerable<T> items)
{
this.CheckReentrancy();
foreach (var item in items) Items.Add(item);
var type = NotifyCollectionChangedAction.Reset;
var colChanged = new NotifyCollectionChangedEventArgs(type);
var countChanged = new PropertyChangedEventArgs("Count");
OnPropertyChanged(countChanged);
OnCollectionChanged(colChanged);
}
}
I don't know very well what exactly is happening here and why these events occur. This is a solutiom I put together after some research on google and stackoverflow.
Now if I bind an instance of my class to say LongListSelector
, then after dynamically adding items through InsertRange
to ObservableCollectionPlus
, the anchored scroll position is LongListSelector
sent to it from the top.
If I add items in the standard way: foreach (var item in items) collection.Add(item);
then the position is LongListSelector
not shifted. But, of course, this way I get the overhead with the DataBinding notification, in which this is not desired.
Apparently there is something wrong with my current solution. How can I implement InsertRange
that will behave exactly like foreach (var item in items) collection.Add(item);
but will only send a DataBinding notification once and won't do weird things to bind the scroll position of the object?
source to share
It might be because you send a notification NotifyCollectionChangedAction.Reset
, it might just NotifyCollectionChangedAction.Add
work, maybe :)
public class ObservableRangeCollection<T> : ObservableCollection<T>
{
public void AddRange(IEnumerable<T> collection)
{
foreach (var i in collection)
{
Items.Add(i);
}
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, collection.ToList()));
}
}
source to share
I recently used this on a project ...
public class RangeObservableCollection<T> : ObservableCollection<T>
{
private bool _suppressNotification = false;
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (!_suppressNotification)
base.OnCollectionChanged(e);
}
public void AddRange(IEnumerable<T> list)
{
if (list == null)
throw new ArgumentNullException("list");
_suppressNotification = true;
foreach (T item in list)
{
Add(item);
}
_suppressNotification = false;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
source to share
It took me ages, the problem was always that the arguments were being passed to the NotifyCollectionChangedEventArgs ctor. Depending on the action, there are many different factors that take different arguments. Seems like it finally works for me: https://github.com/lolluslollus/Utilz/blob/master/Utilz/SwitchableObservableCollection.cs
source to share