简体   繁体   中英

ScrollViewer is disabling virtualization thus causing slow performance in WPF

When I populate a ListView with 10000 rows of data, it is takes around 1 minute to launch the dialog. If I understand correctly, it is happening because ScrollViewer is turning off the virtualization of ListView (child). If I remove ScrollViewer , the dialog gets launched within 5 second.

My problem is I don't want to remove ScrollViewer and virtualization should work for ListView .

<Grid>
    <!--if we remove this scrollviewer then performance will drastically improve-->
     <ScrollViewer  HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
        <ListView Name="variablelist" Grid.ColumnSpan="4"  ItemsSource="{Binding VariableList}" 
                  SelectedItem="{Binding SelectedRow}" IsEnabled="{Binding ListViewVariablesIsEnabled}" 
                  SelectionMode="Single" Foreground="Black" ScrollViewer.CanContentScroll="True" 
                  ScrollViewer.VerticalScrollBarVisibility="Visible"  Margin="0,26,0,10" Grid.RowSpan="2" 
                  KeyDown="variablelist_KeyDown">
            <ListView.View>
                <GridView>
                    <GridViewColumn  Width="{Binding VariableNameWidth, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                        <GridViewColumnHeader Content="{x:Static p:Resources.listviewColumnName}" Command="{Binding SortCommand}" CommandParameter="Name" HorizontalContentAlignment="Left"/>
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Path=Name}" TextTrimming="CharacterEllipsis" ToolTip="{Binding Path=Name}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn  Width="{Binding VariableScopeWidth, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                      <GridViewColumnHeader Content="{x:Static p:Resources.listviewColumnScope}" Command="{Binding SortCommand}" CommandParameter="Scope" HorizontalContentAlignment="Left"/>
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Path=Scope}" TextTrimming="CharacterEllipsis" ToolTip="{Binding Path=Scope}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>                           
                </GridView>
            </ListView.View>
        </ListView>
    </ScrollViewer>
</Grid>

From the code mentioned below based on the type of tab, Usercontrol mentioned above containing Scrolllviewer and Listview is getting launched. I have used Scrollviewer to scroll in case of usercontrol Zoom.

<Grid >
            <Grid.RowDefinitions>
                <RowDefinition MaxHeight="20"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
                <Grid.LayoutTransform>
                    <ScaleTransform ScaleX="{Binding ElementName=ZoomSlider, Path=Value}" 
                                ScaleY="{Binding ElementName=ZoomSlider, Path=Value}" />
                </Grid.LayoutTransform>               
                <TextBlock Name="TitleBar" Text="{Binding Title}" ></TextBlock>
            </Border>
            <TabControl x:Name="pTAB" Grid.Row="1"
                    ItemsSource="{Binding TabItems}" 
                    SelectedItem="{Binding SelectedTab}">
                <TabControl.Resources>
                    <Style TargetType="{x:Type TabItem}">
                        <Setter Property="VerticalAlignment" Value="Bottom"/>                       
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type TabItem}">
                                    <Grid>
                                        <Border Name="Border"
                                            HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
                                            <TextBlock x:Name="TitleContent"
                                                   VerticalAlignment="Center" 
                                                   HorizontalAlignment="Center" 
                                                   Text="{TemplateBinding Header}">
                                            </TextBlock>
                                        </Border>
                                    </Grid>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </TabControl.Resources>
            </TabControl>
        </Grid>

        <Slider x:Name="ZoomSlider" Grid.Row="1" Orientation="Horizontal" 
                Minimum="1.0" Maximum="2.0" LargeChange="0.25" SmallChange="0.01"  Value="1.0" Visibility="Hidden" />
    </Grid>

Already tried things:

 <ListView Name="variablelist" Grid.ColumnSpan="4"  ItemsSource="{Binding VariableList}" 
         SelectedItem="{Binding SelectedRow}" IsEnabled="{Binding ListViewVariablesIsEnabled}" 
         SelectionMode="Single" Foreground="Black" ScrollViewer.CanContentScroll="True" 
         ScrollViewer.VerticalScrollBarVisibility="Visible"  Margin="0,26,0,10" Grid.RowSpan="2" 
         KeyDown="variablelist_KeyDown" VirtualizingPanel.IsVirtualizing="True" 
  VirtualizingPanel.IsVirtualizingWhenGrouping="True"
  VirtualizingPanel.VirtualizationMode="Recycling">
 ......
</ListView> 

Setting up Maxheight of Listview inside constructor worked for me. Previously i was setting up the Maxheight inside SizechangedEvent,thats why while loading it was not working and causing performance issue. And i have also used VirtualizingPanel.IsVirtualizingWhenGrouping="True" VirtualizingPanel.VirtualizationMode="Recycling" with Listview. So moral of the story is you can Manually enable virtualization in ListView present inside Scrollviewer.

You do not have to do any of that. ListView supports scrolling and virtualization by default.

<ListView ItemsSource="{Binding BigList}">
    <ListView.View>
        <GridView>
            <GridViewColumn DisplayMemberBinding="{Binding}"/>
        </GridView>
    </ListView.View>
</ListView>

public class MainWindowViewModel : INotifyPropertyChanged
{
    public IEnumerable<string> BigList { get; }

    public MainWindowViewModel()
    {
        var list = new List<string>();
        for (int i = 0; i < 10000; i++)
            list.Add(i.ToString());
        BigList = list;
    }
}

This will load almost instantly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM