Я реализовал свой собственный ObservableDictionary
, так как: A) меня не устраивал код, который я видел, как другие публикуют, и B) хотел практиковаться. Насколько я могу судить, все работает правильно, включая уведомление слушателей, но по какой-то причине ListView
, который я пытаюсь использовать для отображения содержимого, не обновляется.
Насколько я понимаю, он отслеживает изменения с помощью INotifyCollectionChanged
. В качестве проверки работоспособности я прикрепил прослушиватель к событию CollectionChanged
при инициализации страницы, и он запускается правильно, когда я добавляю элементы, даже если ListView
ничего не отображает. Я знаю, что настроил XAML правильно - если я повторно установлю ItemsSource
в коде после добавления всего в словарь, все будет отображаться правильно; аналогично, замена ObservableDictionary
на встроенный ObservableCollection
(не касаясь XAML) отлично работает даже без этого ручного вмешательства, если я изменяю параметры двухэлементного словаря .Add(...)
, чтобы он соответствовал одноэлементному коллекционному.
Сравнение моего исходного кода для _ 10_, единственное существенное отличие Я вижу, что они включают индекс добавленного объекта, но даже добавление его в мой код ничего не меняет.
Чтобы извлечь соответствующий код, моя (правда, несколько переработанная) система запуска событий:
Tuple<bool, TValue> SendAddEvents(Func<bool> preTest, Func<Tuple<bool, TValue>> action, KeyValuePair<TKey, TValue> item) {
if (preTest.Invoke()) {
#if (SUPPORT_PROPERTYCHANGING_EVENT)
PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(nameof(Keys)));
PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(nameof(Values)));
PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(nameof(Count)));
#endif
OnAdding(item);
}
var result = action.Invoke();
if (result.Item1) {
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add,
item
));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Keys)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Values)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count)));
OnAdd(item);
}
return result;
}
И (насколько я могу судить) официальная система:
protected override void InsertItem(int index, T item)
{
CheckReentrancy();
base.InsertItem(index, item);
OnPropertyChanged(CountString);
OnPropertyChanged(IndexerName);
OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index);
}
private void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index)
{
OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index));
}
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (CollectionChanged != null)
{
using (BlockReentrancy())
{
CollectionChanged(this, e);
}
}
}
Как я уже сказал, я не вижу существенной разницы между ними. Я упускаю что-то очевидное, или есть что-то особенное в том, как ListView
обрабатывает наблюдаемые коллекции, которые кто-то знает, как обойти?
РЕДАКТИРОВАТЬ: Для справки элемент в XAML привязан к следующей строке; строка с нулевым индексом содержит TextBlock
, который я использую, чтобы указать, когда коллекция полностью заполнена. Однако, как я сказал выше, простое изменение типа свойства «Библиотека» с ObservableDictionary<string, StorageFile>
на ObservableCollection<string>
(и ObservableCollection<StorageFile>
ничем не отличается) заставляет все работать без моего прикосновения к XAML.
<ListView ItemsSource="{Binding Library, ElementName=page}" Grid.Row="1" />