2017-02-21 2 views
0

Ich habe eine benutzerdefinierte TreeView mit mehreren Spalten. Alles hat gut funktioniert, bis du viele Gegenstände im Baum hast.Virtualisierung für benutzerdefinierte Strukturansicht

Ich habe versucht, Virtualisierung zu ermöglichen, indem VirtualizingPanel.IsVirtualizing="True" tun (Wird VirtualizingStackPanel.IsVirtualizing, wenn Sie < .NET 4.5) sind aber nicht nur nicht beschleunigen, ist es die Ladezeit noch schlimmer tatsächlich.
An einem normalen TreeView hat diese Eigenschaft den Trick, aber ich nicht einen Weg finden, um es auf meine Art Baum

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; 
    } 
} 
an die Arbeit

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> 

ich die ItemPanel versucht Templating VirtualizingStackPanel zu sein, und es hat auch nicht geholfen.

Ich entferne den Expander Teil, da es nicht relevant ist. Sie können auf den übergeordneten Knoten doppelklicken, um die Struktur zu erweitern, und das Laden der untergeordneten Elemente dauert sehr lange.

Antwort

1

Auf der TreeListView Stil, auf der Eltern Scroll des Itemspresenter, setzen CanContentScroll = „True“:

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

Auf der TreeListViewItem Stil, müssen Sie etwas namens „Expander“ (aus irgendeinem Grund mir unbekannt haben - vielleicht sucht irgendein Stil/Code danach?). Nur eine ToggleButton im Stackpanel Stil setzen:

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

Dies ist die komplette 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> 

ich einen Test2 DataViewColum und habe eine Data2 Eigenschaft auf die Node-Klasse hinzugefügt, um sicherzustellen, dass es funktioniert (und es tut). Hier sind die Änderungen am Code:

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 - Die Vorlage, die VS für mich gemacht (während ich dies heraus wurde Bezifferung), legen Sie die CanContentScroll = „True“ in einen Setter auf einem Auslöser für VirtualizingPanel.IsVirtualizing wenn es wahr ist. Etwas wie dieses:

<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

hätte nie gedacht CanContentScroll könnte möglicherweise einen Effekt auf diese haben. Lebensretter – Steve

Verwandte Themen