2017-02-16 5 views
2

Я пытаюсь создать пользовательскую коллекцию, которая реализует INotifyCollectionChanged и сообщает о массовых изменениях во внутреннем списке элементов с течением времени. Это часть более крупного проекта, но мне удалось создать пример приложения, чтобы продемонстрировать эту проблему. Следуйте приведенным ниже инструкциям и объясните в конце:ListView в UWP имеет непредвиденное поведение, когда INotifyCollectionChanged сообщает о массовых изменениях

1) Откройте визуальную студию 2015 и создайте пустое универсальное приложение Windows с помощью Build 14393 и назовите его «SampleApp», чтобы мы имели одно и то же пространство имен.

2) Скопируйте следующий код Main.xaml

<Page x:Class="SampleApp.MainPage" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:local="using:SampleApp" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     mc:Ignorable="d"> 

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 
     <ListView ItemsSource="{x:Bind Items}" Margin="40"/> 
    </Grid> 
</Page> 

3) Скопируйте следующий код Main.xaml.cs:

using System.Collections.Generic; 
using System.Collections.Specialized; 
using System.ComponentModel; 
using System.Threading.Tasks; 
using Windows.UI.Xaml; 

namespace SampleApp 
{ 
    public sealed partial class MainPage 
    { 
     public FakeCollection Items { get; } = new FakeCollection(); 

     public MainPage() 
     { 
      InitializeComponent(); 

      Loaded += OnLoaded; 
     } 

     private async void OnLoaded(object sender, RoutedEventArgs e) 
     { 
      await Items.Begin(); 
     } 
    } 

    public class FakeCollection : List<string>, INotifyCollectionChanged, INotifyPropertyChanged 
    { 
     public event NotifyCollectionChangedEventHandler CollectionChanged; 
     public event PropertyChangedEventHandler PropertyChanged; 


     public async Task Begin() 
     { 
      var set1 = CreateSet(1, 10); 
      var set2 = CreateSet(11, 15); 

      AddRange(set1); 

      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count")); 
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item[]")); 
      CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, set1, 0)); 


      await Task.Delay(2000); 

      InsertRange(5, set2); 

      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count")); 
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item[]")); 
      CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, set2, 5)); 
     } 

     public List<string> CreateSet(int start, int end) 
     { 
      var list = new List<string>(); 

      for (var i = start; i <= end; i++) 
      { 
       list.Add($"Item {i}"); 
      } 

      return list; 
     } 
    } 
} 

FakeCollection просто List<string> и реализует INotifyPropertyChanged и INotifyCollectionChanged. Он используется в привязке ListView в xaml.

При загрузке главной страницы вызывается метод Begin() и он просто создает список строк, называемых «Item 1», «Item 2», ... «Item 10», добавляет их в список и затем уведомляет изменение коллекции на все 10 предметов. Это прекрасно работает.

Однако после ожидания 2 секунды создается другой набор «Пункт 11», «Пункт 12», ... «Пункт 15», и они вставляются в индекс 5. Мы сообщаем об изменении коллекции снова в позиции 5 с новым набором строк.

Я бы ожидать ListView, чтобы показать точный порядок найденный во внутренней коллекции FakeCollection, которая:

Item 1,2,3,4,5,11,12,13,14,15 , 6,7,8,9,10

Вместо этого он показывает, как

Item 1,2,3,4,5,11,6,7,8,9,10,7, 8,9,10 ????

Что здесь произошло? Похоже, что он добавил первый элемент из поднятого события, а затем просто повторил последние четыре!

Есть ли трюк для совершения ListView Работа с массовым сбором?

ответ

1

Интересно! Похоже, CollectionChanged не работает, когда вы пытаетесь добавить сразу несколько элементов. Я думаю, вы должны сделать что-то вроде этого -

for (var i = 0; i < set2.Count; i++) 
{ 
    CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, set2, i + 5)); 
} 
+0

К сожалению, это было бы просто превратить его в стандартный '' ObservableCollection . Не идеально. Сообщите об этом Microsoft. – Laith

+0

На самом деле выглядит так, как с WPF. Не думайте, что они изменят поведение. –

Смежные вопросы