2017-02-21 3 views
0

Я создал собственный TreeView с несколькими столбцами. Все хорошо работало до тех пор, пока в нем не будет много предметов.virtualization for custom treeview

Я попытался включить виртуализацию, делая VirtualizingPanel.IsVirtualizing="True" (Будет VirtualizingStackPanel.IsVirtualizing если вы < .NET 4.5), но не только не ускорить его, он на самом деле сделал время загрузки еще хуже.
На нормальной TreeView это свойство делает трюк, но я не могу найти способ, чтобы заставить его работать на моем обычае Tree

TreeViewItem.cs

public class TreeListViewItem : TreeViewItem 
{ 
    protected override DependencyObject GetContainerForItemOverride() 
    { 
     return new TreeListViewItem(); 
    } 

    protected override bool IsItemItsOwnContainerOverride(object item) 
    { 
     return item is TreeListViewItem; 
    } 
} 

TreeListView.cs

public class TreeListView : TreeView 
{ 
    public GridViewColumnCollection Columns { get; set; } 
    public TreeListView() 
    { 
     Columns = new GridViewColumnCollection(); 
    } 

    protected override DependencyObject GetContainerForItemOverride() 
    { 
     return new TreeListViewItem(); 
    } 

    protected override bool IsItemItsOwnContainerOverride(object item) 
    { 
     return item is TreeListViewItem; 
    } 
} 

Node.cs

public class Node 
{ 
    public string Data { get; set; } 
    public List<Node> Children { get; set; } 
    public Node(string data) 
    { 
     Data = data; 
     Children = new List<Node>(); 
    } 
} 

ViewModel.cs

public class ViewModel 
{ 
    public ObservableCollection<Node> Nodes { get; private set; } 
    public ViewModel() 
    { 
     Nodes = new ObservableCollection<Node>(); 
     Node parent = new Node("Parent"); 

     for (int i = 0; i < 5000; i++) 
      parent.Children.Add(new Node(i.ToString())); 

     Nodes.Add(parent); 
    } 
} 

MainWindow.xaml

<Window x:Class="WPFTest.MainWindow" 
     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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:WPFTest" 
     Title="Test" 
     mc:Ignorable="d" 
     Width="200"> 
    <Window.DataContext> 
     <local:ViewModel/> 
    </Window.DataContext> 
    <Window.Resources> 
     <Style TargetType="local:TreeListView"> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="local:TreeListView"> 
         <Border BorderBrush="{TemplateBinding BorderBrush}" 
          BorderThickness="{TemplateBinding BorderThickness}"> 
          <ScrollViewer VerticalScrollBarVisibility="Disabled"> 
           <DockPanel> 
            <GridViewHeaderRowPresenter Columns="{Binding Path=Columns, RelativeSource={RelativeSource TemplatedParent}}" 
                 DockPanel.Dock="Top"/> 
            <ScrollViewer HorizontalScrollBarVisibility="Disabled" 
              VerticalScrollBarVisibility="Auto" 
              DockPanel.Dock="Bottom"> 
             <ItemsPresenter/> 
            </ScrollViewer> 
           </DockPanel> 
          </ScrollViewer> 
         </Border> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 

     <Style TargetType="local:TreeListViewItem"> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="local:TreeListViewItem"> 
         <StackPanel> 
          <Border Name="Bd" 
           Background="{TemplateBinding Background}" 
           BorderBrush="{TemplateBinding BorderBrush}" 
           BorderThickness="{TemplateBinding BorderThickness}" 
           Padding="{TemplateBinding Padding}"> 
           <GridViewRowPresenter x:Name="PART_Header" 
                Content="{TemplateBinding Header}" 
                Columns="{Binding Path=Columns, RelativeSource={RelativeSource AncestorType={x:Type local:TreeListView}}}" > 
           </GridViewRowPresenter> 
          </Border> 
          <ItemsPresenter x:Name="ItemsHost" /> 
         </StackPanel> 
         <ControlTemplate.Triggers> 
          <Trigger Property="IsExpanded" Value="false"> 
           <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed"/> 
          </Trigger> 
         </ControlTemplate.Triggers> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 
    </Window.Resources> 
    <Grid> 
     <local:TreeListView ItemsSource="{Binding Nodes}" VirtualizingPanel.IsVirtualizing="True"> 
      <TreeView.ItemTemplate> 
       <HierarchicalDataTemplate ItemsSource="{Binding Children}"/> 
      </TreeView.ItemTemplate> 
      <local:TreeListView.Columns> 
       <GridViewColumn Header="Test" Width="150"> 
        <GridViewColumn.CellTemplate> 
         <DataTemplate> 
          <DockPanel> 
           <TextBlock Text="{Binding Data}"/> 
          </DockPanel> 
         </DataTemplate> 
        </GridViewColumn.CellTemplate> 
       </GridViewColumn> 
      </local:TreeListView.Columns> 
     </local:TreeListView> 
    </Grid> 
</Window> 

Я попытался шаблонирования ItemPanel быть VirtualizingStackPanel и это не помогло.

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

ответ

1

О стиле TreeListView, на ItemsPresenter материнской ScrollViewer, установите CanContentScroll = «True»:

<ScrollViewer CanContentScroll="True" 
    HorizontalScrollBarVisibility="Disabled" 
    VerticalScrollBarVisibility="Auto" 
    DockPanel.Dock="Bottom"> 
    <ItemsPresenter/> 
</ScrollViewer> 

В стиле TreeListViewItem, вам нужно иметь что-то под названием «расширителей» (по какой-то неизвестной причине мне - возможно, какой-то стиль/код его ищет?). Просто поместите ToggleButton в StackPanel стиле в:

<StackPanel> 
    <ToggleButton x:Name="Expander" Width="0" /> 
    <Border Name="Bd" ... /> 
    .... 
</StackPanel> 

Вот полный XAML:

<Window x:Class="WpfApplication88.MainWindow" 
     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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:WpfApplication88" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.DataContext> 
     <local:ViewModel/> 
    </Window.DataContext> 
    <Window.Resources> 
     <Style TargetType="local:TreeListView"> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="local:TreeListView"> 
         <Border BorderBrush="{TemplateBinding BorderBrush}" 
          BorderThickness="{TemplateBinding BorderThickness}"> 
          <ScrollViewer VerticalScrollBarVisibility="Disabled"> 
           <DockPanel> 
            <GridViewHeaderRowPresenter Columns="{Binding Path=Columns, RelativeSource={RelativeSource TemplatedParent}}" 
                DockPanel.Dock="Top"/> 
            <ScrollViewer CanContentScroll="True" 
             HorizontalScrollBarVisibility="Disabled" 
             VerticalScrollBarVisibility="Auto" 
             DockPanel.Dock="Bottom"> 
             <ItemsPresenter/> 
            </ScrollViewer> 
           </DockPanel> 
          </ScrollViewer> 
         </Border> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 

     <Style TargetType="local:TreeListViewItem"> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="local:TreeListViewItem"> 
         <StackPanel> 
          <ToggleButton x:Name="Expander" Width="0" /> 
          <Border Name="Bd" 
           Background="{TemplateBinding Background}" 
           BorderBrush="{TemplateBinding BorderBrush}" 
           BorderThickness="{TemplateBinding BorderThickness}" 
           Padding="{TemplateBinding Padding}"> 
           <GridViewRowPresenter x:Name="PART_Header" 
                Content="{TemplateBinding Header}" 
                Columns="{Binding Path=Columns, RelativeSource={RelativeSource AncestorType={x:Type local:TreeListView}}}" > 
           </GridViewRowPresenter> 
          </Border> 
          <ItemsPresenter x:Name="ItemsHost" /> 
         </StackPanel> 
         <ControlTemplate.Triggers> 
          <Trigger Property="IsExpanded" Value="false"> 
           <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed"/> 
          </Trigger> 
         </ControlTemplate.Triggers> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 
    </Window.Resources> 
    <Grid> 
     <local:TreeListView ItemsSource="{Binding Nodes}" VirtualizingPanel.IsVirtualizing="True"> 
      <TreeView.ItemTemplate> 
       <HierarchicalDataTemplate ItemsSource="{Binding Children}"/> 
      </TreeView.ItemTemplate> 
      <local:TreeListView.Columns> 
       <GridViewColumn Header="Test" Width="150"> 
        <GridViewColumn.CellTemplate> 
         <DataTemplate> 
          <DockPanel> 
           <TextBlock Text="{Binding Data}"/> 
          </DockPanel> 
         </DataTemplate> 
        </GridViewColumn.CellTemplate> 
       </GridViewColumn> 
       <GridViewColumn Header="Test 2" Width="150"> 
        <GridViewColumn.CellTemplate> 
         <DataTemplate> 
          <DockPanel> 
           <TextBlock Text="{Binding Data2}"/> 
          </DockPanel> 
         </DataTemplate> 
        </GridViewColumn.CellTemplate> 
       </GridViewColumn> 
      </local:TreeListView.Columns> 
     </local:TreeListView> 
    </Grid> 
</Window> 

Я добавил Test2 DataViewColum и добавил свойство data2 к классу Node, чтобы убедиться, что он работал (и это так). Вот изменения в коде:

public class ViewModel 
{ 
    public ObservableCollection<Node> Nodes { get; private set; } 
    public ViewModel() 
    { 
     Nodes = new ObservableCollection<Node>(); 
     Node parent = new Node("Parent", "Parent2"); 

     for (int i = 0; i < 5000; i++) 
      parent.Children.Add(new Node(i.ToString(), (i * i).ToString())); 

     Nodes.Add(parent); 
    } 
} 

public class Node 
{ 
    public string Data { get; set; } 
    public string Data2 { get; set; } 

    public List<Node> Children { get; set; } 
    public Node(string data, string data2) 
    { 
     Data = data; 
     Data2 = data2; 
     Children = new List<Node>(); 
    } 
} 

FYI - шаблон, который VS сделал для меня (в то время как я был выяснить это), положить CanContentScroll = «True» в инкубаторе на спусковой крючок для VirtualizingPanel.IsVirtualizing когда это правда. Что-то вроде этого:

<Style TargetType="local:TreeListView"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="local:TreeListView"> 
       <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" 
        BorderThickness="{TemplateBinding BorderThickness}"> 
        <DockPanel> 
         <GridViewHeaderRowPresenter Columns="{Binding Path=Columns, RelativeSource={RelativeSource TemplatedParent}}" 
              DockPanel.Dock="Top"/> 
         <ScrollViewer x:Name="_tv_scrollviewer_" HorizontalScrollBarVisibility="Disabled" 
           VerticalScrollBarVisibility="Auto" 
           DockPanel.Dock="Bottom"> 
          <ItemsPresenter/> 
         </ScrollViewer> 
        </DockPanel> 
       </Border> 
       <ControlTemplate.Triggers> 
        <Trigger Property="VirtualizingPanel.IsVirtualizing" Value="True"> 
         <Setter Property="CanContentScroll" TargetName="_tv_scrollviewer_" Value="True"/> 
        </Trigger> 
       </ControlTemplate.Triggers> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 
+0

никогда не думал о CanContentScroll, возможно, повлияет на это. Жизнь спасателя – Steve