2013-04-12 4 views
9

Сегодня я решил, наконец, попробовать виртуализованный TreeView. Для этого требуется привязка. Поэтому я решил получить 2 теста вещей - HierarchicalDataTemplate, основанный на видах + типов.Ошибка прокрутки в Virtualized TreeView

Я создал базовый класс для некоторых данных. Создал 2 производных класса из базового класса. Сделано 2 HierarchicalDataTemplate (1 для каждого производного класса), чтобы получить различное форматирование узлов. И бегущая популяция 10 тыс. Узлов двух типов.

Классы:

public class ListItem_Generic 
{ 
    public string Name { get; protected set; } 
    public ListItem_Generic(string Name = "") { this.Name = Name; } 
} 

public class ListItem_Single : ListItem_Generic 
{ 
    public ListItem_Single(string Name = "") : base(Name) { } 
} 

public class ListItem_Multi : ListItem_Generic 
{ 
    public List<ListItem_Generic> Items { get; protected set; } 
    public ListItem_Multi(string Name = "", List<ListItem_Generic> Items = null) 
     : base(Name) 
    { 
     if (Items == null) 
      this.Items = new List<ListItem_Generic>(); 
     else 
      this.Items = new List<ListItem_Generic>(Items); 
    } 
} 

Генерация 10k узлов 1-го уровня с некоторыми детьми, переплетные:

public MainWindow() 
    { 
     InitializeComponent(); 

     // Create a list of sample items and populate them 
     var lst = new List<ListItem_Generic>(); 

     int MaxHeaders = 10000; 
     var rnd = new Random(); 
     // Now generate 10 000 records. First select random amount of headers 
     int HeadersCount = rnd.Next(MaxHeaders); 

     for (int i = 0; i < HeadersCount; i++) 
     { 
      var Childrencount = rnd.Next(100); 
      var children = new List<ListItem_Generic>(); 
      for (int j = 0; j < Childrencount; j++) 
       children.Add(new ListItem_Single("Child #"+j+" of parent #"+i)); 
      lst.Add(new ListItem_Multi("Header #" + i + " (" + Childrencount + ")", children)); 
     } 
     for (int i = 0; i < MaxHeaders - HeadersCount; i++) 
      lst.Add(new ListItem_Single("Line #" + i)); 

     // Bind lstView to lst 
     lstView.ItemsSource = lst; 
     lstView.UpdateLayout(); 
    } 

XAML с HierarchicalDataTemplates:

<Window x:Class="Test_DataTemplates.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:loc="clr-namespace:Test_DataTemplates" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <TreeView Name="lstView" VirtualizingPanel.IsVirtualizing="True"> 
      <TreeView.Resources> 
       <HierarchicalDataTemplate DataType="{x:Type loc:ListItem_Multi}" ItemsSource="{Binding Path=Items}"> 
        <Border Background="RosyBrown"> 
         <TextBlock Text="{Binding Path=Name}" Foreground="White" FontWeight="Bold"/> 
        </Border> 
       </HierarchicalDataTemplate> 
       <HierarchicalDataTemplate DataType="{x:Type loc:ListItem_Single}"> 
        <TextBlock Text="{Binding Path=Name}"/> 
       </HierarchicalDataTemplate> 
      </TreeView.Resources> 
     </TreeView> 
    </Grid> 
</Window> 

Все работает точно:

  • TreeView получает виртуализировать (легко заметить по памяти след + время загрузки)
  • узлов, полученные из типов правильно отформатирован

Тем не менее, когда прокрутка скажем заголовок # 1000 и расширяя его - положение прокрутки переместится в другое место, делая расширенный узел, а его дети НЕ видны.

Что я сделал не так? Есть ли способ исправить это?

Обновление: Удаление виртуализации также удаляет прокрутку.

+0

связаны: http://stackoverflow.com/questions/4074475/scrolling-bug-in-wpf-virtualized- treeview –

+0

, имеющий эту же проблему здесь – Laie

+0

@ Jee-heonOh imho, TreeView не слишком подходит для виртуализации. Я бы посоветовал вместо этого использовать ListBox/ListView. Легко имитировать древовидный вид с помощью шаблонов и имитировать расширение уровня/сворачивание с добавлением/удалением элементов в/из простого (наблюдаемого) списка. В TreeListView имеется несколько примеров. Если вы склонны использовать TreeView (обратите внимание, что он может виртуализировать только иерархию первого уровня) - см. Обходной путь на сайте Microsoft, опубликованный одним из участников. Он переопределяет несколько событий treeviewitem, чтобы привести их в поле зрения по мере необходимости, что решает проблему прокрутки. – user2274578

ответ

0

Try выключая (не на) Переработка

VirtualizingStackPanel.VirtualizationMode="Standard" 

Оптимизация статье относится к превращению его в

How to: Improve the Performance of a TreeView

+0

Оба режима Standart и Recycling производят такую ​​же ошибку с прокруткой Blam. – user2274578

+0

Shoot Я оставлю его до тех пор, пока вы не получите ответ, чтобы люди знали, что это не ответ. – Paparazzi

0

Я был бы признателен, если some1 просто проверить это в своей среде и подтвердите эту проблему. Кроме того, играя вокруг немного нашел другое странное поведение:

  • измененного режим Standart
  • реализован IsExpanded двухстороннего связывания (не уверен, если это требуется вообще)

Следующей пробег программа:

  • Расширьте заголовок с некоторым большим числом, как 1000 - скроллер прыжков в другом месте

Перекладка программа (для чистоты эксперимента)

  • Expand один из первых заголовков, как # 2.
  • Расширьте заголовок с некоторым большим числом, как 1000 - скроллер остается в нужном месте ...

Расширение один из первых узлов выглядят как обходной путь.

1

После того, как у меня возникли проблемы с виртуализацией дерева в C# WPF (включая основную проблему, которая только виртуализируется только на первом уровне) - я не смог найти правильное исправление. Microsoft приняла отчет об ошибке и ответила, что проблема прокрутки будет исправлена ​​в одном из будущих выпусков.

Что касается окончательного решения этого для меня лично - я переключился на собственную реализацию ListTreeView, то есть с помощью List и моделирования дерева. Это позволило решить все проблемы с виртуализацией и с помощью прокрутки. Единственная проблема - удаление множества элементов после свертывания узла дерева. Я должен был выполнить проверку, если проще или быстрее просто создать новый список, а не удалять элементы 1 на 1.

0

Я нашел решение на MSDN. По-видимому, это как-то связано с шаблоном TreeView по умолчанию. Следующее исправление мерцания полосы прокрутки и прекращение случайных узлов при быстром прокрутке.

<Style x:Key="{x:Type TreeView}" TargetType="{x:Type TreeView}"> 
    <Setter Property="TreeView.Background" Value="Transparent"/> 
    <Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/> 
    <Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling"/> 
    <Setter Property="TreeView.SnapsToDevicePixels" Value="True" /> 
    <Setter Property="TreeView.OverridesDefaultStyle" Value="True" /> 
    <Setter Property="ItemsControl.ItemsPanel"> 
     <Setter.Value> 
      <ItemsPanelTemplate> 
       <VirtualizingStackPanel IsItemsHost="True"/> 
      </ItemsPanelTemplate> 
     </Setter.Value> 
    </Setter> 
    <Setter Property="TreeView.Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="TreeView"> 
       <ScrollViewer Focusable="False" CanContentScroll="True" Padding="4"> 
        <ItemsPresenter HorizontalAlignment="Stretch"/> 
       </ScrollViewer> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

Я пробовал быстро прокручивать и больше не замечал проблемы. Удивительно то, что вам даже не нужно избавляться от вашей виртуализации.

+0

Не можете добавить ссылку, где вы нашли ее на сайте MSDN? Меня особенно интересовала бы специфика того, где шаблон по умолчанию пошел не так. –

0

Согласно https://msdn.microsoft.com/en-us/library/system.windows.controls.scrollunit(v=vs.110).aspx (ScrollUnit Enumeration) существует два возможных значения. По умолчанию используется значение «Pixel», что вызывает проблемы с прокруткой. Переход на 'Пункт', как показано ниже решает вопрос:

VirtualizingStackPanel.ScrollUnit = "Пункт"

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