Пользовательский наблюдаемый не обновляет UWP ListView

Я реализовал свой собственный 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" />

person Sam May    schedule 08.04.2017    source источник
comment
Как ты привязываешься к списку? Как выглядит код привязки xaml?   -  person Laith    schedule 09.04.2017
comment
@Laith Добавил это в исходный пост.   -  person Sam May    schedule 09.04.2017


Ответы (1)


Посмотрев на ваш исходный код, я заметил, что ваш ObservableDictionaryBase<TKey, TValue> не реализует IList<TValue>. Для ListView.

Что бы ни было связано с ListView.ItemsSource, необходимо реализовать как INotifyCollectionChanged, так и IList. Когда он получает уведомление об изменениях в словаре, он пытается получить изменения через индексатор (т.е. page.Library[n]).

В конечном итоге это приведет вас к реализации, подобной KeyedCollection<TKey, TValue>, где у вас есть упорядоченный список ключевых элементов.

person Laith    schedule 09.04.2017
comment
Готово, спасибо! Я предполагал, что IEnumerable было бы достаточно. Теперь мне просто нужно заставить это работать; жаль, что встроенный OrderedDictionary не имеет общей версии (и ни один из пакетов Nuget не поддерживает .NETStandard). По крайней мере, C # предоставляет LinkedListNode. - person Sam May; 09.04.2017