WPF UI Thread blocked with large collection

2020-03-31 02:24发布

I have a WPF application built using MVVM; one of the Views contains a collection of models that can be between 200-500 in length, each of the models are mapped to a RepositoryViewModel and bound to the 'Repository.xaml' view in a stack panel.

The top level View (Main.xaml) is as follows:

<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 is as follows:

<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>

The above works perfectly as I require, the issue is the time WPF takes to render the controls- once each of the RepositoryViewModel's are added to the RepositoryViewModel ObservableCollection the entire UI freezes for 3-5 seconds whilst the controls are rendered.

Whilst trying to isolate the issue I noticed that by removing the textbox's the render time dramatically decreases but removing the binding on the textbox's does not make a noticeable difference. Swapping the textbox's for labels made little difference.

Is the collection size simply to large to expect WPF to handle quickly or am I missing something that is increasing the render time? I did consider having a SharedSizeGroup with a MaxWidth may be the culprit but removing did not improve performance.

Thanks.

标签: c# wpf xaml mvvm
1条回答
仙女界的扛把子
2楼-- · 2020-03-31 02:33

Look into adding virtualization to your ItemsControl. This way it only renders the items in view rather than all of them.

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

I believe you'd also need to remove the ItemsControl from the StackPanel and ScrollViewer, as they'll give the ItemsControl infinite space to render, and render the virtualization useless.

I see you're using a WrapPanel for your ItemsPanelTemplate, so you may need to roll your own virtualized panel, or check out some other controls (haven't used these myself).

查看更多
登录 后发表回答