Реализуйте AddRange на ObservableCollection с надлежащей поддержкой DataBinding
Я хотел бы, чтобы мой собственный потомок ObservableCollection
поддерживать AddRange
метод. Вот что у меня сейчас есть:
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);
}
}
У меня нет особых знаний о том, что именно здесь происходит и почему возникают эти события. Это решение, которое я собрал после некоторых исследований Google и Stackru.
Теперь, если я свяжу экземпляр моего класса, чтобы сказать LongListSelector
затем, после динамического добавления элементов через InsertRange
в ObservableCollectionPlus
в переплете LongListSelector
Позиция прокрутки отправляется наверх.
Если я добавлю элементы стандартным способом: foreach (var item in items) collection.Add(item);
затем LongListSelector
позиция не сдвигается. Но, конечно, таким образом, я получаю уведомления о связывании данных, что нежелательно.
Видимо, что-то не так в моем текущем решении. Как я могу реализовать InsertRange
который будет вести себя так же, как foreach (var item in items) collection.Add(item);
но будет ли запускать уведомление DataBinding только один раз и не будет делать странные вещи с позицией прокрутки связанного объекта?
4 ответа
Это может быть потому, что вы отправляете NotifyCollectionChangedAction.Reset
уведомление, может быть, просто NotifyCollectionChangedAction.Add
будет работать, может быть:)
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()));
}
}
Я использовал это в проекте недавно...
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));
}
}
Проблема, с которой вы сталкиваетесь при использовании DataBinding, может быть связана с тем, что вы не вызываете PropertyChanged для индексатора (имя свойства "Item[]"), как это происходит в ObservableCollection в соответствии с исходным кодом.
Вы также можете взглянуть на хорошую реализацию ObservableRangeCollection Джеймса Монтемагно здесь, на GitHub, она наследуется от ObservableColection и включает методы AddRange и ReplaceRange со всеми уведомлениями PropertyChaged и CollectionChanged, необходимыми для DataBinding.
Это занимало у меня много времени, проблема всегда была в том, что аргументы передавались в ctor NotifyCollectionChangedEventArgs. Есть много разных ctors, которые принимают разные аргументы в зависимости от действия. Следующее, кажется, наконец-то работает для меня: https://github.com/lolluslollus/Utilz/blob/master/Utilz/SwitchableObservableCollection.cs