виртуализация вложенных контейнеров (virtualizingstackpanel) на одной родительской полосе прокрутки в WPF - PullRequest
2 голосов
/ 30 июля 2009

Я как бы закодировал себя в этом. Я пишу пользовательский элемент управления WPF, который похож на TreeListView, описанный в В этой статье MSDN , а также во многих других местах в сети. На данный момент довольно большая куча этой вещи - обычай, и она вполне соответствует моим целям, за исключением виртуализации. Мои переопределенные шаблоны TreeView и TreeViewItem используют VirtualizingStackPanel s для представления своих предметов, и я убедился, что все это создается, как и ожидалось. Виртуализация работает правильно на элементах корневого уровня (готовятся только элементы пользовательского интерфейса для тех, которые в настоящее время видимы в ScrollViewer), а материал TreeView заботится о том, чтобы не генерировать элементы для свернутых узлов. Проблема возникает при расширении узла - все элементы готовятся для каждого дочернего узла, даже тысячи, которые находятся за пределами экрана.

Мне показалось, что все, что мне нужно было, это каким-то образом установить свойство scrollowner внутренних вложенных VirtualizingStackPanel s в то же основное представление прокрутки, к которому VSP корневого уровня подключается по умолчанию, но я читаю плакат MSFT. здесь говорят, что это не сработает.

К сожалению, эта штука медленная, как грязь, без виртуализации, поэтому мне нужно найти какое-то решение. Любые предложения будут с благодарностью.

Ответы [ 2 ]

1 голос
/ 16 марта 2017

Я знаю, что это старый вопрос, но он все еще был актуален для меня.

В моем случае я подумал, что TreeView не обрежет его, потому что мне нужно ровно два слоя, а типы отображаемых элементов различны для двух слоев. Кроме того, я рефакторинг списка Expander с, поэтому я думал более одномерный.

Но потом я понял, что вы можете настроить ItemTemplate из TreeView, чтобы включить свой собственный HierarchicalDataTemplate, и что вы можете настроить ItemTemplate этого HierarchicalDataTemplate с вашим собственным DataTemplate. .. Престо! Ровно два слоя с разными вещами в каждом!

Так что я хочу сказать, что TreeView достаточно гибок, чтобы вы не пытались создать свой собственный элемент управления.

Вот что я сделал:

XAML:

<Page x:Class="Foo.Views.TreePage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:Foo.Views"
      xmlns:viewModel="clr-namespace:Foo.ViewModels"
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"
      Title="Tree page"
      d:DataContext="{d:DesignInstance Type=viewModel:TreeModel}">
    <TreeView
        VirtualizingPanel.IsVirtualizing="True"
        VirtualizingPanel.VirtualizationMode="Recycling"
        ScrollViewer.CanContentScroll="True"
        VirtualizingPanel.ScrollUnit="Pixel"
        ItemsSource="{Binding Values}"><!-- IList<Person> -->
        <TreeView.ItemTemplate><!-- Template for first layer, which has a HierarchicalDataTemplate so that this layer will expand -->
            <HierarchicalDataTemplate
                ItemsSource="{Binding Expenses}"><!-- IList<Expense> -->
                <HierarchicalDataTemplate.ItemTemplate><!-- Template for the second layer, which has a DataTemplate instead of HierarchicalDataTemplate so that this layer won't expand -->
                    <DataTemplate>
                        <TextBlock Text="{Binding Amount}"/><!-- Expense amount in dollars -->
                    </DataTemplate>
                </HierarchicalDataTemplate.ItemTemplate>

                <TextBlock Text="{Binding Name}"/><!-- Person name -->
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
</Page>

Класс Person:

public class Person
{
    public string Name { get; set; }
    public List<Expense> Expenses { get; set; }
}

Класс Expense:

public class Expense
{
    public double Amount { get; set; }
}

Вот как это выглядит:

Screenshot of the above code in action

Я проверил это с помощью Snoop , чтобы доказать, что это виртуализация пользовательского интерфейса. Вот количество загруженных TreeViewItem с, когда приложение маленькое:

Screenshot showing the number of elements when the app is small

... А вот количество загруженных TreeViewItem с, когда приложение работает в полноэкранном режиме (оно продолжает выходить за рамки этого фрагмента, но вы понимаете):

Screenshot showing that there are more elements when the app is fullscreen

Теперь достаточно просто стилизовать вещи так, чтобы вложенный слой выглядел так, как я хочу!

Редактировать: я только что проверил, что TreeView виртуализирует все его слои, а не только первый слой.

0 голосов
/ 31 июля 2009

У меня была ссылка на список того, что не нужно делать с виртуализированной панелью стека, но по какой-то причине страница вылетает пустой. Вот еще одна страница, которая немного говорит об этом:

http://www.designerwpf.com/2008/02/12/listview-and-listbox-performance-issues/

и даже ссылки на тот, о котором я говорю, но он всегда пуст. если вы посмотрите на этой странице, это ссылка на блог Марка Шурмера. Вот ссылка, если вы хотите попробовать:

http://itknowledgeexchange.techtarget.com/wpf/listview-is-it-really-too-slow/

У Bea Stollnitz также есть несколько статей, которые могут помочь:

Часть 1 часть 2 часть 3

Если вы разместите часть своего кода, кто-то может немного разгадать спагетти, чтобы помочь вам получить лучшую реализацию.

РЕДАКТИРОВАТЬ: нашел ссылку, которая может работать (спасибо archive.org !!!): http://web.archive.org/web/20080104163725/http://itknowledgeexchange.techtarget.com/wpf/listview-is-it-really-too-slow/

...