wpf 如何虚拟化ItemsControl

xfb7svmp  于 2023-10-22  发布在  其他
关注(0)|答案(1)|浏览(134)

我有774个项目的List。当我将它设置为绑定到ItemsSource的ViewModel的Items属性(也是List)时,大约需要10秒以上。

我已经尝试了Virtualizing an ItemsControl?的答案,它没有工作-仍然10秒以上。

这是未经修改的代码。请注意,**ItemsControl位于ScrollViewer**内部。

XAML:

<Grid d:DataContext="{x:Static local:RulesListDesignModel.Instance}" Background="{StaticResource ForegroundLightBrush}">
        <ScrollViewer VerticalScrollBarVisibility="Auto">
            <ItemsControl ItemsSource="{Binding Items}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <local:RulesListItemControl />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </ScrollViewer>
    </Grid>

C#

ViewModelApplication.CurrentRulesListViewModel.Items = mList;

这是根据Virtualizing an ItemsControl?的答案修改代码后的XAML(似乎需要10秒多一点):

<Grid d:DataContext="{x:Static local:RulesListDesignModel.Instance}" Background="{StaticResource ForegroundLightBrush}">
    <ScrollViewer VerticalScrollBarVisibility="Auto">
        <ItemsControl ItemsSource="{Binding Items}"
                      VirtualizingStackPanel.IsVirtualizing="True"
                      ScrollViewer.CanContentScroll="True">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <local:RulesListItemControl />
                </DataTemplate>
            </ItemsControl.ItemTemplate>

            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.Template>
                <ControlTemplate>
                    <Border
        BorderThickness="{TemplateBinding Border.BorderThickness}"
        Padding="{TemplateBinding Control.Padding}"
        BorderBrush="{TemplateBinding Border.BorderBrush}"
        Background="{TemplateBinding Panel.Background}"
        SnapsToDevicePixels="True">
                        <ScrollViewer
                Padding="{TemplateBinding Control.Padding}"
                Focusable="False">
                            <ItemsPresenter
                    SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
                        </ScrollViewer>
                    </Border>
                </ControlTemplate>
            </ItemsControl.Template>
        </ItemsControl>
    </ScrollViewer>
</Grid>
ghg1uchk

ghg1uchk1#

您应该使用ListBoxListView,它们集成了ScrollViewer,并且默认启用了UI虚拟化。没有必要使用更基本的ItemsControl
您应该尝试以下方法来使用UI虚拟化:

<ListBox VirtualizingStackPanel.VirtualizationMode="Recycling" />

VirtualizingStackPanel.VirtualizationMode设置为VirtualizationMode.Recycling可提高滚动性能。
如果你想继续使用ItemsControl(为什么?)您需要重新编写可视化树。
您目前正在使用两个ScrollViewers。一个在模板内部,另一个包裹在ItemsControl周围。请注意,由于ScrollViewer.CanContentScroll默认为false,因此内部ScrollViewer负责禁用UI虚拟化。将CanContentScroll设置为true是必要的,因为它将滚动单位设置为item(而不是pixel)。VirtualizingStackPanel需要知道可见项的数量。
您应该删除外部的ScrollViewer,您的性能应该会显着提高:

<ItemsControl ItemsSource="{Binding Items}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <local:RulesListItemControl />
    </DataTemplate>
  </ItemsControl.ItemTemplate>

  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <VirtualizingStackPanel IsVirtualizing="True"
                              VirtualizationMode="Recycling" />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>

  <ItemsControl.Template>
    <ControlTemplate TargetType="ItemsControl">
      <Border BorderThickness="{TemplateBinding BorderThickness}"
              BorderBrush="{TemplateBinding BorderBrush}"
              Background="{TemplateBinding Background}">
        <ScrollViewer CanContentScroll="True" 
                      Padding="{TemplateBinding Padding}"
                      Focusable="False">
          <ItemsPresenter />
        </ScrollViewer>
      </Border>
    </ControlTemplate>
  </ItemsControl.Template>
</ItemsControl>

但更重要的是专注于您的自定义RulesListItemControl。为每个项目加载此控件。复杂的控件会引入复杂的初始化。应尝试缩减此控件的视觉树。
删除所有不需要的Border,用TextBlock替换Label,重新访问触发器等。目标是减少每个项目容器的呈现时间。
要做到这一点,您需要覆盖用于组成RulesListItemControl的控件的ControlTemplate

相关问题