I am experiencing major performance issues with ListView
whenever I implement grouping. I have found somewhat similar questions on StackOverflow, but none seem to help!
每当我实现分组时,我都会遇到ListView的主要性能问题。我在StackOverflow上发现了一些类似的问题,但似乎都没有帮助!
Here is my current situation (I have simplified my project so there is less noise):
这是我目前的情况(我简化了我的项目,因此噪音更小):
I have a ContentControl
with a ListView
as the child. The ListView
is bound to an ObservableCollection
, which is initially empty. As time passes, objects are added to to the collection (in this example, 500 items are added every 10 seconds using a DispatcherTimer
). The size of the ObservableCollection
will vary, but it's possible the collection could end up being over 25,000 items.
我有一个ContentControl,ListView作为孩子。 ListView绑定到ObservableCollection,它最初是空的。随着时间的推移,对象被添加到集合中(在此示例中,使用DispatcherTimer每10秒添加500个项目)。 ObservableCollection的大小会有所不同,但收集可能最终会超过25,000个项目。
When the ObservableCollection
has less than 2000 (not exact figure), column resizing looks like this:
当ObservableCollection小于2000(不是确切的数字)时,列大小调整如下所示:
However, as more objects are added to the ObservableCollection
, there is a noticeable drop in performance (you need to scroll down for this to occur).
但是,随着更多对象被添加到ObservableCollection中,性能会明显下降(您需要向下滚动才能实现此目的)。
This will eventually lead to the Application
locking up.
这最终将导致应用程序锁定。
I was thinking the problem could be resolved using Virtualization
, so I tried using the following:
我认为可以使用Virtualization解决问题,所以我尝试使用以下内容:
However, nothing seems to work!
Not to mention, VirtualizingPanel.IsVirtualizingWhenGrouping="True"
causes the ListView
to lock up entirely.
但是,似乎什么都没有用!更不用说,VirtualizingPanel.IsVirtualizingWhenGrouping =“True”会导致ListView完全锁定。
I have also looked into Paul McClean's excellent Data Virtualization, however, it does not handle grouping.
我也研究过Paul McClean出色的数据虚拟化,但是它并没有处理分组。
Question: When grouping items in a ListView
, is there a way to resize the columns without drastically affecting the Application's performance?
问题:在ListView中对项目进行分组时,是否有办法调整列的大小而不会显着影响应用程序的性能?
Ideally, I would like to reduce memory overhead, so I am all for implementing some sort of asynchronous solution.
理想情况下,我想减少内存开销,所以我全都是为了实现某种异步解决方案。
XAML:
XAML:
CODE-BEHIND:
后台代码:
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
{
///
/// Interaction logic for MainWindow.xaml
///
public partial class MainWindow : ContentControl
{
private ObservableCollection eventCollection = new ObservableCollection();
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; }
}
}
}
11
Your performance issue is due to not using IsVirtualizingWhenGrouping
您的性能问题是由于未使用IsVirtualizingWhenGrouping
You mentionned that using IsVirtualizingWhenGrouping
was locking your application, and this is a known WPF issue (see : http://connect.microsoft.com/VisualStudio/feedback/details/780146/freeze-when-using-virtualizingpanel-isvirtualizingwhengrouping for more information on this bug happening when having a custom GroupStyle and IsVirtualizingWhenGrouping
set to true)
您提到使用IsVirtualizingWhenGrouping锁定您的应用程序,这是一个已知的WPF问题(请参阅:http://connect.microsoft.com/VisualStudio/feedback/details/780146/freeze-when-using-virtualizingpanel-isvirtualizingwhengrouping获取更多信息将自定义GroupStyle和IsVirtualizingWhenGrouping设置为true时发生此错误
Here is a quick workaroung to solve your issue : You just have to add an expander in the GroupStyle ControlTemplate. You'll then be able to use IsVirtualizingWhenGrouping
and then have good performances when scrolling/Resizing columns.
以下是解决问题的快速工作方法:您只需在GroupStyle ControlTemplate中添加扩展器即可。然后,您可以使用IsVirtualizingWhenGrouping,然后在滚动/调整列时获得良好的性能。
Here is the code that works on my machine : (I put everything directly in MainWindow to simplify a bit)
这是在我的机器上运行的代码:(我将所有内容直接放在MainWindow中以简化一下)
EDIT: Here is a ControlTemplate that "hides" the expander. It's the original one from which I removed the unnecessary parts :
编辑:这是一个“隐藏”扩展器的ControlTemplate。这是我删除不必要部分的原始内容:
You can use it by setting it in the group style :
您可以通过在组样式中设置它来使用它:
2
I think the problem is the ObservableCollection that is bound to your ListView and the case that you are adding 500 items per Add(). Each Add will raise 3 events. 2 NotifyPropertyChanged
-Events for property Count
and property Item[]
and one the NotifyCollectionChanged-Event
of the Collection, what counts up to 1500 events that are raised.
我认为问题是绑定到ListView的ObservableCollection以及每个Add()添加500个项目的情况。每个Add都会引发3个事件。 2 NotifyPropertyChanged - 属性Count和属性Item []的事件以及Collection的NotifyCollectionChanged-Event,最多可计入1500个引发的事件。
I have exchanged the ObservableCollection with my own derived implementation of ObservableCollection that allows me to add a range of items and raise only 3 events once.
我已经使用我自己的ObservableCollection派生实现交换了ObservableCollection,它允许我添加一系列项目并且只引发一次3个事件。
public class SmartCollection : ObservableCollection {
public SmartCollection()
: base() {
}
public SmartCollection(IEnumerable collection)
: base(collection) {
}
public SmartCollection(List list)
: base(list) {
}
public void AddRange(IEnumerable range) {
foreach (var item in range) {
Items.Add(item);
}
this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
this.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public void Reset(IEnumerable range) {
if (range == null) {
throw new ArgumentNullException("range", "range is null");
}
var rangeToAdd = range.ToList();
this.Items.Clear();
AddRange(rangeToAdd);
}
}
Using my Collection i changed your method to add the elements to the collection
使用我的Collection我改变了你的方法,将元素添加到集合中
private SmartCollection eventCollection = new SmartCollection();
private void dispatcherTimer_Tick(object sender, EventArgs e) {
List newEvents = new List(500);
for(var i = 0; i <500; i++){
newEvents.Add(new Event {
Name = string.Format("Name_{0}", eventCollection.Count + i),
Date = DateTime.Now.ToString("MM.dd.yy HH:mm"),
SecOnds= Convert.ToInt32(DateTime.Now.ToString("ss")),
Desc = "Description"
});
}
eventCollection.AddRange(newEvents);
}
0
I'm not sure if this answer will suit, but I did get that performance back after setting the VirtualizingPanel.ScrollUnit property to "Item". The problem is, I had a number of visual glitches, which included seeing the Grouping object overlaying the top row when scrolling row-by-row (mouse wheel or key up/down), and the blurring across the rows immediately after scrolling as the renderer kicked in clear up the text.
我不确定这个答案是否适合,但是在将VirtualizingPanel.ScrollUnit属性设置为“Item”之后我确实得到了这个性能。问题是,我有一些视觉故障,其中包括在逐行滚动(鼠标滚轮或键向上/向下)时看到分组对象覆盖顶行,并在滚动后立即在行之间模糊渲染器开始清理文本。
VirtualizingPanel.ScrollUnit="Item"
Edit: Also change the VirtualizationMode back to Standard, VirtualizingPanel.VirtualizatiOnMode="Standard", and the visual glitches almost dissapear. (Having been testing with 50,000 rows).
编辑:还将VirtualizationMode更改回Standard,VirtualizingPanel.VirtualizatiOnMode=“Standard”,并且视觉故障几乎消失。 (已经测试了50,000行)。