【问题标题】:ScrollViewer is disabling virtualization thus causing slow performance in WPFScrollViewer 正在禁用虚拟化,从而导致 WPF 性能下降
【发布时间】:2020-02-11 12:13:47
【问题描述】:

当我用 10000 行数据填充 ListView 时,启动对话框大约需要 1 分钟。如果我理解正确,这是因为ScrollViewer 正在关闭ListView(子)的虚拟化。如果我删除 ScrollViewer,对话框会在 5 秒内启动。

我的问题是我不想删除 ScrollViewer,虚拟化应该适用于 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>

从下面提到的基于选项卡类型的代码中,上面提到的包含 Scrolllviewer 和 Listview 的 Usercontrol 正在启动。在用户控件缩放的情况下,我使用 Scrollviewer 进行滚动。

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

已经尝试过的东西:

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

【问题讨论】:

  • 为什么首先要有那个外部的 ScrollViewer? ListView 默认已经支持滚动,当然也支持虚拟化。
  • 是的,我知道 listview 支持滚动 我正在使用外部滚动查看器在缩放的情况下滚动用户控件
  • 哪个用户控件? ScrollViewer 内部只有一个 ListView。
  • 此代码存在于用户控件中,由于版权原因,我没有提及整个代码。在 scrollviewer 标记内,我还有其他 UI 元素。这就是为什么我不想删除滚动查看器。有没有其他方法可以在不删除滚动查看器的情况下在列表视图中启用虚拟化。
  • 非常感谢@Jonatha Alfaro 在构造函数中设置 Maxheight 对我有用。以前我在 SizechangedEvent 中设置 Maxheight。这就是为什么在加载时它不起作用。我在 Xaml 中使用了带有 Listview 的 VirtualizingPanel.IsVirtualizingWhenGrouping="True" VirtualizingPanel.VirtualizationMode="Recycling"

标签: c# wpf


【解决方案1】:

在构造函数中设置 Listview 的 Maxheight 对我有用。以前我在 SizechangedEvent 中设置 Maxheight,这就是为什么在加载它时它不起作用并导致性能问题。而且我还使用了 VirtualizingPanel.IsVirtualizingWhenGrouping="True" VirtualizingPanel.VirtualizationMode="Recycling" 和 Listview。故事的寓意是您可以在 Scrollviewer 中的 ListView 中手动启用虚拟化。

【讨论】:

    【解决方案2】:

    您不必执行任何操作。 ListView 默认支持滚动和虚拟化。

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

    这几乎会立即加载。

    【讨论】:

    • 是的,我知道 listview 支持滚动 我正在使用外部滚动查看器来滚动用户控件以防缩放我没有提到整个代码。在 scrollviewer 标记内,我还有其他 UI 元素。这就是为什么我不想删除滚动查看器。有没有其他方法可以在不删除滚动查看器的情况下在列表视图中启用虚拟化。
    • 您的 ListView 位于 ScrollViewer 中,因此它会根据需要增长。外层容器的虚拟化将不适用于 ListView。
    • 如果我说得对,你的意思是说外部滚动查看器没有禁用列表视图虚拟化。检查此链接harishasanblog.blogspot.com/2011/02/…
    • 这篇文章很好地解释了它。您将网格放置在 ScrollViewer 中,因此 ListView 可以根据需要增长,并且它永远不会使用它自己的滚动查看器,因此不会发生虚拟化。
    • 您能否展示其他控件并解释缩放的含义。也许您缺少的布局还有另一种方法。
    猜你喜欢
    • 2012-06-23
    • 1970-01-01
    • 1970-01-01
    • 2011-11-07
    • 2011-02-13
    • 2013-11-19
    • 1970-01-01
    • 1970-01-01
    • 2014-08-02
    相关资源
    最近更新 更多