2017-02-21 68 views
0

我制作了一个具有多列的自定义TreeView。一切都运行良好,直到你在树上有很多物品。定制树视图虚拟化

我试着通过做VirtualizingPanel.IsVirtualizing="True"(如果你是< .NET 4.5,将会是VirtualizingStackPanel.IsVirtualizing)来启用虚拟化,但它不仅加速它,它实际上使加载时间变得更糟。
在一个正常的TreeView这个属性做的伎俩,但我无法找到一个方法来得到它在我的自定义工作树

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 =“真”:

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

在TreeListViewItem风格,你需要有一个名为“扩展”(出于某种原因不明我的东西 - 也许有些风格/代码正在寻找它?)。 只要把一个切换按钮的样式的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并添加了数据2属性节点类,以确保它的工作(它的确如此)。下面是修改代码:

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>(); 
    } 
} 

仅供参考 - 即VS为我做(我搞清楚了这一点,同时)的模板,把CanContentScroll =“真”到二传手对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