У меня возникают основные проблемы с производительностью при ListView
всякий раз, когда я реализую группировку. Я нашел несколько похожих вопросов в StackOverflow, но никто не помогает!
Вот моя текущая ситуация (я упростил свой проект, чтобы было меньше шума):
У меня есть ContentControl
с ListView
как ребенок. ListView
привязан к ObservableCollection
, который изначально пуст. По прошествии времени к коллекции добавляются объекты (в этом примере каждые 10 секунд добавляются 500 элементов с помощью DispatcherTimer
). Размер ObservableCollection
будет отличаться, но возможно, что коллекция может содержать более 25 000 элементов.
Если значение ObservableCollection
меньше 2000 (не точная цифра), изменение размера столбца выглядит следующим образом:
Однако, поскольку в ObservableCollection
добавлено больше объектов, наблюдается заметное снижение производительности (вам нужно прокрутить вниз, чтобы это произошло).
Это приведет к блокировке Application
.
Я думал, что проблема может быть решена с помощью Virtualization
, поэтому я попытался использовать следующее:
<ListView x:Name="ListView1"
Style="{DynamicResource lvStyle}"
VirtualizingPanel.IsVirtualizingWhenGrouping="True"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.IsContainerVirtualizable="True"
ScrollViewer.IsDeferredScrollingEnabled="True">
Однако ничего не работает!
Не говоря уже, VirtualizingPanel.IsVirtualizingWhenGrouping="True"
заставляет ListView
полностью блокировать.
Я также рассмотрел Пол МакКлин превосходную виртуализацию данных, однако он не обрабатывает группировку.
Вопрос: При группировке элементов в ListView
существует ли способ изменить размер столбцов без существенного влияния на производительность приложения?
В идеале я хотел бы уменьшить накладные расходы памяти, поэтому я все для реализации своего рода асинхронного решения.
CODE:
XAML:
<ContentControl x:Class="ListViewDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ListViewDemo"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:dat="clr-namespace:System.Windows.Data;assembly=PresentationFramework"
xmlns:Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Classic"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="300">
<ContentControl.Resources>
<Style x:Key="lvStyle" TargetType="{x:Type ListView}">
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
<Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling"/>
<Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="True"/>
<Setter Property="ListView.ItemsSource" Value="{Binding}"/>
<Setter Property="ListView.View">
<Setter.Value>
<GridView>
<GridViewColumn Header="Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Date">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Date}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Desc">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Desc}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</Setter.Value>
</Setter>
</Style>
</ContentControl.Resources>
<Grid>
<ListView x:Name="ListView1"
Style="{DynamicResource lvStyle}"
VirtualizingPanel.IsVirtualizingWhenGrouping="True"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.IsContainerVirtualizable="True"
ScrollViewer.IsDeferredScrollingEnabled="True">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<DockPanel>
<Border DockPanel.Dock="Top">
<TextBlock x:Name="groupItem"
Text="{Binding ItemCount, StringFormat={}({0} Results)}"></TextBlock>
</Border>
<ItemsPresenter DockPanel.Dock="Bottom"></ItemsPresenter>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
</Grid>
</ContentControl>
КОД-ЗА:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace ListViewDemo
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : ContentControl
{
private ObservableCollection<Event> eventCollection = new ObservableCollection<Event>();
public MainWindow()
{
InitializeComponent();
DispatcherTimer dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 0, 10);
dispatcherTimer.Start();
ListView1.ItemsSource = eventCollection;
ListView1.Items.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Descending));
ListView1.Items.SortDescriptions.Add(new SortDescription("Date", ListSortDirection.Descending));
ListView1.Items.GroupDescriptions.Add(new PropertyGroupDescription("Seconds"));
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
for(var i = 0; i < 500; i++){
eventCollection.Add(new Event
{
Name = string.Format("Name_{0}", eventCollection.Count),
Date = DateTime.Now.ToString("MM.dd.yy HH:mm"),
Seconds = Convert.ToInt32(DateTime.Now.ToString("ss")),
Desc = "Description"
});
}
}
public class Event
{
public string Name { get; set; }
public string Date { get; set; }
public int Seconds { get; set; }
public string Desc { get; set; }
}
}
}