WPF TreeView 和虚拟化问题

标签 wpf xaml treeview virtualization

我有一个具有 2 级层次结构的 TreeView。 TreeView Item 已经竞标到特定类的属性。基本上,我正在获取 ObservableCollection 列表并将该列表指定为我的 TreeView ItemsSource。最初 treeView 可见性设置为 Collapsed,在分配 ItemsSource 后,TreeView 可见性设置为 Visible。此时应用程序卡住了大约 40 秒(它基本上加载了 1000 多个父项和每个父项的 5-10 个子项)。

代码隐藏是

PopulateTreeView()
{
    // ocListToDisplay is my ObservableCollection
    tvES.ItemsSource = ocListToDisplay;

    //App Freezes at this bit when making the tvES Visible from Collapsed
    tvES.Visibility = System.Windows.Visibility.Visible; 
}

我的XAML是这样的

 <ScrollViewer Name="scContainer" VerticalAlignment="Stretch" 
               HorizontalAlignment="Stretch">
    <StackPanel>
        <StackPanel.Resources>
            <exportImport:TreeViewDashboard x:Key="dataItems"/>
            <HierarchicalDataTemplate DataType="{x:Type exportImport:TreeViewDashboard}"
                                      ItemsSource="{Binding Path=Components}">

                <Grid  Margin="2" >
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition ></ColumnDefinition>
                        <ColumnDefinition ></ColumnDefinition>
                        <ColumnDefinition ></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <CheckBox Name="checkbx" Grid.Column="0" Margin="2" 
                              Tag="{Binding Path=Tag}" 
                              Checked="OnCheck" Unchecked="OnUnCheck"></CheckBox>
                    <Image Margin="2" Grid.Column="1" Source="{Binding Path=ImageUrl}"  
                           Height="14" Width="16" ></Image>
                    <TextBlock Margin="2" Grid.Column="2" Text="{Binding Path=Name}"
                              FontWeight="Bold" />
                </Grid>

                <HierarchicalDataTemplate.ItemTemplate>
                    <DataTemplate>
                        <Grid  Margin="2" >
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition ></ColumnDefinition>
                                <ColumnDefinition ></ColumnDefinition>
                                <ColumnDefinition ></ColumnDefinition>
                            </Grid.ColumnDefinitions>
                            <CheckBox Name="checkbx" Grid.Column="0" Margin="2" 
                                      Tag="{Binding Path=Tag}" 
                                      Checked="OnCheck" Unchecked="OnUnCheck"/>
                            <Image Margin="2" Grid.Column="1" 
                                   Source="{Binding Path=ImageUrl}" 
                                   Height="14" Width="16" />
                            <TextBlock Margin="2" Grid.Column="2" 
                                  Text="{Binding Path=Name}" FontWeight="Bold" />
                        </Grid>
                    </DataTemplate>
                </HierarchicalDataTemplate.ItemTemplate>

            </HierarchicalDataTemplate>
        </StackPanel.Resources>

        <--same result if you set IsVirtualizing to True/False App freezes for 40 sec-->
        <TreeView Name="tvES"  BorderThickness="0" 
              ItemsSource="{Binding Source={StaticResource dataItems}}"
              VirtualizingStackPanel.IsVirtualizing="False"
              VirtualizingStackPanel.VirtualizationMode="Recycling"
              TreeViewItem.Expanded="item_Expanded"
              TreeViewItem.Collapsed="item_Collapsed" >
            <TreeView.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel/>
                </ItemsPanelTemplate>
            </TreeView.ItemsPanel>
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}">
                    <Setter Property="IsExpanded" Value="False" />
                </Style>
            </TreeView.ItemContainerStyle>
        </TreeView>
    </StackPanel>  
 </ScrollViewer>

我还尝试获取 TreeView 中的视觉对象数量。在 IsVisualizing="True"和 IsVisualizing="False" 这两种情况下,我得到相同数量的 Visuals 计数,这清楚地表明我做错了什么。

从树中获取视觉计数的代码

  //In my case I am passing tvES as  DependencyObject
    private static int GetVisualCount(DependencyObject visual)
    {
        int visualCount = 1;
        int childCount = VisualTreeHelper.GetChildrenCount(visual);

        for (int i = 0; i < childCount; i++)
        {
            DependencyObject childVisual = VisualTreeHelper.GetChild(visual, i);
            visualCount += GetVisualCount(childVisual);
        }

        return visualCount;
    } 

我最终得到了 TreeView ,但问题是我的应用程序在填充 TreeView 时卡住了..!!任何人都有解决办法吗?我有 scollviewer,这会导致虚拟化问题吗?

PS: TreeView Generated 是这样的,但是有 1000 个相似的节点

enter image description here

更新:

我正在阅读有关 VirtualizingStackPanel 的文章,其中写道:“StackPanel 中的虚拟化仅在面板中包含的项目控件创建其自己的项目容器时发生。您可以通过使用数据绑定(bind)来确保发生这种情况。在创建项目容器的场景中并添加到项目控件中,VirtualizingStackPanel 与 StackPanel 相比没有性能优势。”

如果我遵循的上述方法是正确的,有人可以建议我吗?我非常确定我是我错了..

最佳答案

您忘记设置 ScrollViewer.CanContentScroll=True。这是虚拟化的。并将 IsVirtualizing 设置回 true

关于WPF TreeView 和虚拟化问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22567126/

相关文章:

c# - 带有 Win32 父窗口的 WPF OpenFileDialog;窗口在关闭时没有重新获得焦点

c# - System.IO.File.Move--如何等待移动完成?

WPF 隐藏顶部面板布局

c# - XAML 中的预处理器条件编译

wpf - 是否有任何工具支持 xaml 中的 resx 本地化重构?

c# - 将所有 treeView 父级和子级复制到另一个 treeView c# WinForms

c++ - 向 Qt 树模型中添加一些自定义数据

c# - WPF 中的跨表格数据绑定(bind)

c# - 文档错误或 .NET 中的错误

wpf - 我需要这样的 Wpf TreeView