Skip to main content
 首页 » 编程设计

c#之WPF UI 线程被大集合阻塞

2024年05月22日41zengkefu

我有一个使用 MVVM 构建的 WPF 应用程序;其中一个 View 包含一组长度在 200-500 之间的模型,每个模型都映射到 RepositoryViewModel 并绑定(bind)到堆栈面板中的“Repository.xaml” View 。

顶层 View (Main.xaml)如下:

<Window.Resources> 
    <DataTemplate DataType="{x:Type home:RepositoryViewModel}"> 
        <vw:Repository /> 
    </DataTemplate> 
<Window.Resources> 
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" Margin="5 40 5 5"> 
    <StackPanel Orientation="Vertical" Grid.IsSharedSizeScope="True"> 
        <ItemsControl ItemsSource="{Binding Repositories}"> 
            <ItemsControl.ItemsPanel> 
                <ItemsPanelTemplate> 
                    <WrapPanel Orientation="Horizontal" /> 
                </ItemsPanelTemplate> 
            </ItemsControl.ItemsPanel> 
        </ItemsControl> 
    </StackPanel> 
</ScrollViewer> 

Repository.xaml UserControl如下:

<Grid Margin="5" Visibility="{Binding Model.Visibility}" > 
    <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="Auto" /> 
        <ColumnDefinition SharedSizeGroup="WrapPanelGroup" /> 
        <ColumnDefinition Width="Auto" /> 
    </Grid.ColumnDefinitions> 
 
    <StackPanel Grid.Column="1">      
        <!--Textbox is used to allow user to select the text. Changing to Label does not help with rendering issues-->        
        <TextBox Background="Transparent" BorderThickness="0" Text="{Binding Model.Name}" IsReadOnly="True" 
                 TextWrapping="Wrap" FontSize="18" MaxWidth="300" /> 
        <TextBox Background="Transparent" BorderThickness="0" Text="{Binding Model.Url}" IsReadOnly="True" 
                 TextWrapping="Wrap" FontSize="8" MaxWidth="300" Foreground="DarkGray" /> 
    </StackPanel> 
    <Button Grid.Column="2" Content="Checkout" Command="{Binding CheckoutCommand}" Visibility="{Binding Model.SingleCheckoutVisible}"/> 
    <CheckBox Grid.Column="2" IsChecked="{Binding Model.IsChecked}" Visibility="{Binding Model.BulkCheckoutVisible}"/> 
</Grid> 

以上内容完全符合我的要求,问题是 WPF 渲染控件所花费的时间 - 一旦将每个 RepositoryViewModel 添加到 RepositoryViewModel ObservableCollection 整个 UI 在呈现控件时卡住 3-5 秒。

在尝试隔离问题时,我注意到通过删除文本框的渲染时间会显着减少,但删除文本框上的绑定(bind)不会产生明显的差异。将文本框换成标签几乎没有什么区别。

集合大小是否只是为了让 WPF 能够快速处理而过大,还是我遗漏了一些会增加渲染时间的东西?我确实考虑过具有 MaxWidth 的 SharedSizeGroup 可能是罪魁祸首,但删除并没有提高性能。

谢谢。

请您参考如下方法:

考虑将虚拟化添加到您的 ItemsControl。这样它只会呈现 View 中的项目而不是所有项目。

<ItemsControl VirtualizingStackPanel.IsVirtualizing="True" 
              ScrollViewer.CanContentScroll="True"> 
    <ItemsControl.ItemsPanel> 
        <ItemsPanelTemplate> 
            <VirtualizingStackPanel /> 
        </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
</ItemsControl> 

我相信您还需要从 StackPanel 和 ScrollViewer 中删除 ItemsControl,因为它们会为 ItemsControl 提供无限的渲染空间,并使虚拟化变得无用。

我看到您正在为 ItemsPanelTemplate 使用 WrapPanel,因此您可能需要推出自己的虚拟化面板,或者查看一些 other controls (我自己没用过)。