WPF — использование CollectionViewSource с УЖЕ сгруппированными данными

У меня есть ViewModel, которая используется в Windows 8, Android и iOS как часть проекта Xamarin. Теперь мне нужно отобразить эту виртуальную машину в ListView в WPF.

Эта виртуальная машина предоставляет некоторые уже сгруппированные данные как ObservableCollection<GroupedResult<string, SearchResult>>. GroupResult имеет свойство Key (String) и свойство IEnumerable Source.

С помощью ListView в Windows 8 я могу назначить эти данные в CollectionViewSource (CVS), сообщить CVS путь к свойству Items PropertyPath("Source"), и он отлично работает.

Однако WPF, кажется, хочет, чтобы несгруппированный список был передан в его CVS, чтобы он мог сгруппировать все это сам. Как мне сообщить WPF CVS, что виртуальная машина уже содержит сгруппированные данные?


person Pat Long - Munkii Yebee    schedule 12.12.2016    source источник


Ответы (1)


Я боюсь, что класс System.Windows.Data.CollectionViewSource в WPF не имеет свойства IsSourceGrouped или эквивалентного, поэтому вы не можете сказать, что данные уже сгруппированы.

В основном у вас есть два варианта.

  1. Разгруппируйте исходную коллекцию и задайте для свойства Source объекта CollectionViewSource несгруппированную коллекцию и добавьте PropertyGroupDescription в ее коллекцию GroupDescriptions, как обычно: https://msdn.microsoft.com/en-us/library/ms742542(v=vs.110).aspx

  2. Установите источник для сгруппированной коллекции и определите ItemTemplate для объектов группировки:

    public MainWindow()
    {
        InitializeComponent();
        List<User> items = new List<User>();
        items.Add(new User() { Name = "John Doe", Age = 42, Sex = SexType.Male });
        items.Add(new User() { Name = "Jane Doe", Age = 39, Sex = SexType.Female });
        items.Add(new User() { Name = "Sammy Doe", Age = 13, Sex = SexType.Male });
    
        var result =
            from x in items
            group x by x.Sex into g
            orderby g.Key
            select g;
    
        listBox.ItemsSource = result;
    }
    

   <ListBox x:Name="listBox">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Expander Header="{Binding Key}">
                    <ListBox ItemsSource="{Binding}">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <StackPanel>
                                    <TextBlock Text="{Binding Name}"/>
                                </StackPanel>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                </Expander>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
person mm8    schedule 12.12.2016
comment
Я рад предположить, что источник сгруппирован, и настроить шаблоны в соответствии с ним. Я буду отображать в ListView, а не в ListBox, если я хочу, чтобы разделы всегда были расширены, если не пусты, можете ли вы предложить контейнер, отличный от Expander? - person Pat Long - Munkii Yebee; 12.12.2016
comment
Что не так с расширителем? Вы можете установить для его IsExpanded значение true, чтобы он расширялся по умолчанию. И если вы не хотите иметь возможность разворачивать/сворачивать группы, вы можете просто удалить расширитель и использовать ListBox или ItemsControl в качестве корневой панели DataTemplate. - person mm8; 12.12.2016
comment
Я пытаюсь имитировать GroupStyle HidesIfEmpty=True, который я так успешно использовал в Win8. Как вы предложили, я заменю расширитель на что-то другое. Спасибо - person Pat Long - Munkii Yebee; 12.12.2016
comment
У меня все работает по варианту 2, но очень медленно с большими наборами данных. Мне интересно, не привело ли это к тому, что я потерял виртуализацию. Я предполагаю, но похоже, что свойство Name каждой отдельной строки в сгруппированном наборе читается, а не только те, которые необходимы для рисования текущего представления. - person Pat Long - Munkii Yebee; 13.12.2016
comment
Прочитав этот вопрос, stackoverflow.com/questions/12569506/listbox-not-virtualizing Я вижу, что для внутреннего ListBox\ListView требуется установить MaxHeight, чтобы вы по-прежнему получали виртуализацию. Вы должны отметить, что в вашем ответе - person Pat Long - Munkii Yebee; 13.12.2016
comment
Виртуализация будет применяться, если только внешний ListBox не является дочерним элементом StackPanel или какой-либо другой панели, которая измеряет свои дочерние элементы с бесконечной высотой. Если вы поместите ListBox, который я разместил, в окне с сеткой в ​​качестве его корневой панели, вы должны увидеть, что виртуализация работает должным образом. - person mm8; 13.12.2016
comment
У меня есть ListView во всплывающем окне, по-видимому, есть проблемы с виртуализацией во всплывающих окнах. Я посмотрю, можно ли это исправить. Я пробовал это с вариантом 1 (сведенные данные), и это та же проблема. - person Pat Long - Munkii Yebee; 13.12.2016
comment
Я действительно не понимаю, как это связано с вашим первоначальным вопросом о том, как отображать уже сгруппированные данные, но поскольку всплывающее окно — это собственное окно, вы должны либо установить высоту самого всплывающего окна, либо ListBox в нем, чтобы включить виртуализацию. Виртуализация не поддерживается, если верхняя панель не имеет ограничений по высоте. - person mm8; 13.12.2016