Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ListView Resize Columns Performance Issues (Grouping)

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!


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.

When the ObservableCollection has less than 2000 (not exact figure), column resizing looks like this:

enter image description here

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

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:

<ListView x:Name="ListView1"
                  Style="{DynamicResource lvStyle}"
                  VirtualizingPanel.IsVirtualizingWhenGrouping="True"
                  VirtualizingPanel.IsVirtualizing="True"
                  VirtualizingPanel.IsContainerVirtualizable="True"
                  ScrollViewer.IsDeferredScrollingEnabled="True">

However, nothing seems to work!

Not to mention, VirtualizingPanel.IsVirtualizingWhenGrouping="True" causes the ListView to lock up entirely.

I have also looked into Paul McClean's excellent Data Virtualization, however, it does not handle grouping.


Question: When grouping items in a ListView, is there a way to resize the columns without drastically affecting the Application's performance?

Ideally, I would like to reduce memory overhead, so I am all for implementing some sort of asynchronous solution.


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>

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

    }

}
like image 873
Dom Avatar asked Apr 26 '13 21:04

Dom


2 Answers

Your performance issue is due to not using 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)

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.

Here is the code that works on my machine : (I put everything directly in MainWindow to simplify a bit)

<Window x:Class="WpfApplication21.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>

        <Style x:Key="lvStyle" TargetType="{x:Type ListView}" >

            <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>
    </Window.Resources>

    <Grid>
        <ListView x:Name="ListView1"
                  Style="{DynamicResource lvStyle}"
                  VirtualizingPanel.IsVirtualizing="True"
                  VirtualizingPanel.IsVirtualizingWhenGrouping="True">
            <ListView.GroupStyle>
                <GroupStyle>
                    <GroupStyle.ContainerStyle>
                        <Style TargetType="{x:Type GroupItem}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type GroupItem}">
                                        <Expander IsExpanded="True">
                                            <DockPanel>
                                                <Border DockPanel.Dock="Top">
                                                    <TextBlock x:Name="groupItem"
                                                                Text="{Binding ItemCount, StringFormat={}({0} Results)}"></TextBlock>
                                                </Border>
                                                <ItemsPresenter x:Name="groupItemPresenter" DockPanel.Dock="Bottom"></ItemsPresenter>
                                            </DockPanel>
                                        </Expander>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </GroupStyle.ContainerStyle>
                </GroupStyle>
            </ListView.GroupStyle>
        </ListView>
    </Grid>
</Window>

EDIT: Here is a ControlTemplate that "hides" the expander. It's the original one from which I removed the unnecessary parts :

<ControlTemplate x:Key="CustomExpanderControlTemplate" TargetType="{x:Type Expander}">
        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="3" SnapsToDevicePixels="True">
            <DockPanel>
                <ToggleButton x:Name="HeaderSite" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" DockPanel.Dock="Top" Foreground="{TemplateBinding Foreground}" FontWeight="{TemplateBinding FontWeight}" FontStyle="{TemplateBinding FontStyle}" FontStretch="{TemplateBinding FontStretch}" FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" MinWidth="0" MinHeight="0" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
                    <ToggleButton.FocusVisualStyle>
                        <Style>
                            <Setter Property="Control.Template">
                                <Setter.Value>
                                    <ControlTemplate>
                                        <Border>
                                            <Rectangle Margin="0" SnapsToDevicePixels="True" Stroke="Black" StrokeThickness="1" StrokeDashArray="1 2"/>
                                        </Border>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </ToggleButton.FocusVisualStyle>
                    <ToggleButton.Style>
                        <Style TargetType="{x:Type ToggleButton}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                                        <Border Padding="{TemplateBinding Padding}">
                                            <Grid Background="Transparent" SnapsToDevicePixels="False">
                                                <Grid.ColumnDefinitions>
                                                    <ColumnDefinition Width="*"/>
                                                </Grid.ColumnDefinitions>
                                                <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="0" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="Left" Margin="4,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Center"/>
                                            </Grid>
                                        </Border>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </ToggleButton.Style>
                </ToggleButton>
                <ContentPresenter x:Name="ExpandSite" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" DockPanel.Dock="Bottom" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" Visibility="Collapsed" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
            </DockPanel>
        </Border>
        <ControlTemplate.Triggers>
            <Trigger Property="IsExpanded" Value="True">
                <Setter Property="Visibility" TargetName="ExpandSite" Value="Visible"/>
            </Trigger>
            <Trigger Property="ExpandDirection" Value="Right">
                <Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Right"/>
                <Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Left"/>
                <Setter Property="Style" TargetName="HeaderSite">
                    <Setter.Value>
                        <Style TargetType="{x:Type ToggleButton}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                                        <Border Padding="{TemplateBinding Padding}">
                                            <Grid Background="Transparent" SnapsToDevicePixels="False">
                                                <Grid.RowDefinitions>
                                                    <RowDefinition Height="19"/>
                                                    <RowDefinition Height="*"/>
                                                </Grid.RowDefinitions>
                                                <Grid>
                                                    <Grid.LayoutTransform>
                                                        <TransformGroup>
                                                            <RotateTransform Angle="-90"/>
                                                        </TransformGroup>
                                                    </Grid.LayoutTransform>
                                                    <Ellipse x:Name="circle" Fill="Transparent" HorizontalAlignment="Center" Height="19" Stroke="DarkGray" VerticalAlignment="Center" Width="19"/>
                                                    <Path x:Name="arrow" Data="M1,1.5L4.5,5 8,1.5" HorizontalAlignment="Center" SnapsToDevicePixels="False" Stroke="#FF666666" StrokeThickness="2" VerticalAlignment="Center"/>
                                                </Grid>
                                                <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="Center" Margin="0,4,0,0" Grid.Row="1" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Top"/>
                                            </Grid>
                                        </Border>
                                        <ControlTemplate.Triggers>
                                            <Trigger Property="IsChecked" Value="True">
                                                <Setter Property="Data" TargetName="arrow" Value="M1,4.5L4.5,1 8,4.5"/>
                                            </Trigger>
                                            <Trigger Property="IsMouseOver" Value="True">
                                                <Setter Property="Stroke" TargetName="circle" Value="#FF3C7FB1"/>
                                                <Setter Property="Fill" TargetName="circle" Value="Transparent"/>
                                                <Setter Property="Stroke" TargetName="arrow" Value="#FF222222"/>
                                            </Trigger>
                                            <Trigger Property="IsPressed" Value="True">
                                                <Setter Property="Stroke" TargetName="circle" Value="#FF526C7B"/>
                                                <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                                                <Setter Property="Fill" TargetName="circle" Value="Transparent"/>
                                                <Setter Property="Stroke" TargetName="arrow" Value="#FF003366"/>
                                            </Trigger>
                                            <Trigger Property="IsEnabled" Value="False">
                                                <Setter Property="Stroke" TargetName="circle" Value="DarkGray"/>
                                                <Setter Property="Fill" TargetName="circle" Value="Transparent"/>
                                                <Setter Property="Stroke" TargetName="arrow" Value="#FF666666"/>
                                            </Trigger>
                                        </ControlTemplate.Triggers>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </Setter.Value>
                </Setter>
            </Trigger>
            <Trigger Property="ExpandDirection" Value="Up">
                <Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Top"/>
                <Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Bottom"/>
                <Setter Property="Style" TargetName="HeaderSite">
                    <Setter.Value>
                        <Style TargetType="{x:Type ToggleButton}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                                        <Border Padding="{TemplateBinding Padding}">
                                            <Grid Background="Transparent" SnapsToDevicePixels="False">
                                                <Grid.ColumnDefinitions>
                                                    <ColumnDefinition Width="19"/>
                                                    <ColumnDefinition Width="*"/>
                                                </Grid.ColumnDefinitions>
                                                <Grid>
                                                    <Grid.LayoutTransform>
                                                        <TransformGroup>
                                                            <RotateTransform Angle="180"/>
                                                        </TransformGroup>
                                                    </Grid.LayoutTransform>
                                                    <Ellipse x:Name="circle" Fill="Transparent" HorizontalAlignment="Center" Height="19" Stroke="DarkGray" VerticalAlignment="Center" Width="19"/>
                                                    <Path x:Name="arrow" Data="M1,1.5L4.5,5 8,1.5" HorizontalAlignment="Center" SnapsToDevicePixels="False" Stroke="#FF666666" StrokeThickness="2" VerticalAlignment="Center"/>
                                                </Grid>
                                                <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="1" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="Left" Margin="4,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Center"/>
                                            </Grid>
                                        </Border>
                                        <ControlTemplate.Triggers>
                                            <Trigger Property="IsChecked" Value="True">
                                                <Setter Property="Data" TargetName="arrow" Value="M1,4.5L4.5,1 8,4.5"/>
                                            </Trigger>
                                            <Trigger Property="IsMouseOver" Value="True">
                                                <Setter Property="Stroke" TargetName="circle" Value="#FF3C7FB1"/>
                                                <Setter Property="Fill" TargetName="circle" Value="Transparent"/>
                                                <Setter Property="Stroke" TargetName="arrow" Value="#FF222222"/>
                                            </Trigger>
                                            <Trigger Property="IsPressed" Value="True">
                                                <Setter Property="Stroke" TargetName="circle" Value="#FF526C7B"/>
                                                <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                                                <Setter Property="Fill" TargetName="circle" Value="Transparent"/>
                                                <Setter Property="Stroke" TargetName="arrow" Value="#FF003366"/>
                                            </Trigger>
                                            <Trigger Property="IsEnabled" Value="False">
                                                <Setter Property="Stroke" TargetName="circle" Value="DarkGray"/>
                                                <Setter Property="Fill" TargetName="circle" Value="Transparent"/>
                                                <Setter Property="Stroke" TargetName="arrow" Value="#FF666666"/>
                                            </Trigger>
                                        </ControlTemplate.Triggers>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </Setter.Value>
                </Setter>
            </Trigger>
            <Trigger Property="ExpandDirection" Value="Left">
                <Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Left"/>
                <Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Right"/>
                <Setter Property="Style" TargetName="HeaderSite">
                    <Setter.Value>
                        <Style TargetType="{x:Type ToggleButton}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                                        <Border Padding="{TemplateBinding Padding}">
                                            <Grid Background="Transparent" SnapsToDevicePixels="False">
                                                <Grid.RowDefinitions>
                                                    <RowDefinition Height="19"/>
                                                    <RowDefinition Height="*"/>
                                                </Grid.RowDefinitions>
                                                <Grid>
                                                    <Grid.LayoutTransform>
                                                        <TransformGroup>
                                                            <RotateTransform Angle="90"/>
                                                        </TransformGroup>
                                                    </Grid.LayoutTransform>
                                                    <Ellipse x:Name="circle" Fill="Transparent" HorizontalAlignment="Center" Height="19" Stroke="DarkGray" VerticalAlignment="Center" Width="19"/>
                                                    <Path x:Name="arrow" Data="M1,1.5L4.5,5 8,1.5" HorizontalAlignment="Center" SnapsToDevicePixels="False" Stroke="#FF666666" StrokeThickness="2" VerticalAlignment="Center"/>
                                                </Grid>
                                                <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="Center" Margin="0,4,0,0" Grid.Row="1" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Top"/>
                                            </Grid>
                                        </Border>
                                        <ControlTemplate.Triggers>
                                            <Trigger Property="IsChecked" Value="True">
                                                <Setter Property="Data" TargetName="arrow" Value="M1,4.5L4.5,1 8,4.5"/>
                                            </Trigger>
                                            <Trigger Property="IsMouseOver" Value="True">
                                                <Setter Property="Stroke" TargetName="circle" Value="#FF3C7FB1"/>
                                                <Setter Property="Fill" TargetName="circle" Value="Transparent"/>
                                                <Setter Property="Stroke" TargetName="arrow" Value="#FF222222"/>
                                            </Trigger>
                                            <Trigger Property="IsPressed" Value="True">
                                                <Setter Property="Stroke" TargetName="circle" Value="#FF526C7B"/>
                                                <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                                                <Setter Property="Fill" TargetName="circle" Value="Transparent"/>
                                                <Setter Property="Stroke" TargetName="arrow" Value="#FF003366"/>
                                            </Trigger>
                                            <Trigger Property="IsEnabled" Value="False">
                                                <Setter Property="Stroke" TargetName="circle" Value="DarkGray"/>
                                                <Setter Property="Fill" TargetName="circle" Value="Transparent"/>
                                                <Setter Property="Stroke" TargetName="arrow" Value="#FF666666"/>
                                            </Trigger>
                                        </ControlTemplate.Triggers>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </Setter.Value>
                </Setter>
            </Trigger>
            <Trigger Property="IsEnabled" Value="False">
                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>

You can use it by setting it in the group style :

<Expander IsExpanded="True" Template="{DynamicResource CustomExpanderControlTemplate}">
like image 140
Sisyphe Avatar answered Oct 16 '22 08:10

Sisyphe


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.

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.

    public class SmartCollection<T> : ObservableCollection<T> {
        public SmartCollection()
            : base() {

        }

        public SmartCollection(IEnumerable<T> collection)
            : base(collection) {

        }

        public SmartCollection(List<T> list)
            : base(list) {

        }

        public void AddRange(IEnumerable<T> 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<T> 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

private SmartCollection<Event> eventCollection = new SmartCollection<Event>();

private void dispatcherTimer_Tick(object sender, EventArgs e) {
  List<Event> newEvents = new List<Event>(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);
}
like image 2
Jehof Avatar answered Oct 16 '22 08:10

Jehof