WPF TreeView和虚拟化问题

3
我有一个带有两级层次结构的TreeView。 TreeView项绑定到特定类的属性。基本上,我得到ObservableCollection列表,并将该列表分配为我的TreeView ItemsSource。最初,treeView可见性设置为Collapsed,分配ItemsSource后,TreeView可见性设置为Visible。此时应用程序会卡顿约40秒钟(基本上是加载数千个父项和每个父项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>

我也尝试获取树形视图中的视觉元素数量。但在 IsVisualizing="True" 和 IsVisualizing="False" 的情况下,我得到了相同的 Visuals count 数量,这明显表明我做错了什么。

获取树形结构中的视觉元素数量的代码

  //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时我的应用程序会冻结..!! 有人知道解决方法吗?我已经有了滚动条,这会对虚拟化造成问题吗?
PS:生成的TreeView看起来像这样,但有数千个类似的节点
更新:
我正在阅读VirtualizingStackPanel,其中提到:“仅当面板中包含的项控件创建自己的项容器时,堆栈面板中的虚拟化才会发生。您可以通过使用数据绑定来确保发生这种情况。在创建并添加到项控件的项容器的情况下,VirtualizingStackPanel与StackPanel相比不会提供任何性能优势。”
有人能建议我是否应该遵循上述方法吗?我非常确定我在错误的方向上...
1个回答

2

您忘记设置ScrollViewer.CanContentScroll=True,这是虚拟化的关键。同时将IsVirtualizing设置为true


设置ScrollViewer.CanContentScroll=True和IsVirtualizing为true后,应用程序仍然会冻结。有任何想法吗? - Vinnie
@Vinnie 可能与您的 数据 有关。您如何查询子项?它们是否是按需加载的?检索需要花费一些时间,即从数据库查询吗?如果是这样,那么这是一个 数据虚拟化 问题。如果不是,则可能是 UI 虚拟化 的问题。此外,请尝试删除当前实现,即 GetVisualCount - 123 456 789 0
@III 是的,这些数据是从数据库中检索出来的,这是一个后台进程 - 如果检索到的数据很大,可能需要几分钟时间..! GetVisualCount 是供我参考的 - 它并不在实际实现中。这可能是绑定图像和复选框到树视图项的问题..!! - Vinnie
@Vinnie 你有一个示例项目可以共享吗?因为我无法复现您遇到的问题。 - 123 456 789 0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接