【问题标题】:WPF UI Thread blocked with large collectionWPF UI 线程被大型集合阻塞
【发布时间】:2015-11-05 15:13:37
【问题描述】:

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

顶层视图(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呈现控件的秒数。

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

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

谢谢。

【问题讨论】:

  • 更新:增加渲染时间的罪魁祸首是因为我在 WrapPanel 内的每个用户控件上都有一个动态的高度和宽度,设置一个固定的高度/宽度会大大增加渲染时间。

标签: c# wpf xaml mvvm


【解决方案1】:

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

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

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

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

【讨论】:

  • 另外不要忘记在运行时使用 WPF 树可视化器查看控件,以确认虚拟化实际上工作正常,它有一个很容易破坏的坏习惯。跨度>
  • 谢谢,我会做一些关于虚拟化的研究。我忘了提到还有一个搜索将Model.Visibility(在 Repository.xaml 中使用)的值设置为可见或折叠,但我认为虚拟化支持?
  • 意味着您基本上希望某些项目根据不同的条件被过滤掉?查看将您的 ItemsControl 绑定到 CollectionViewSource。这可以处理您想要呈现视图的所有不同方式,包括排序和过滤。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-03
  • 2019-08-18
  • 2012-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多