I have a DataGrid bound to an observable list of objects. If I also have an ItemsControl bound to that list the sorting performance (by clicking the DataGrid header) is very bad (in the order of a few seconds for the sample below). When the ItemsControl is not bound to the same list, then sorting is instant.
Here is some sample code that exhibits this behaviour
namespace LargeDataGridViewTest
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainPresenter();
}
}
public class MainPresenter : INotifyPropertyChanged
{
private readonly ObservableCollection<Item> _items = new ObservableCollection<Item>();
public IEnumerable<Item> Items { get { return _items; } }
public MainPresenter()
{
for (var i = 0; i < 10000; i++)
_items.Add(new Item());
}
}
public class Item : INotifyPropertyChanged
{
public int Random { get; private set; }
private static readonly Random Rand = new Random();
public Item()
{
Random = Rand.Next(0, 1000000);
}
}
}
And the corresponding XAML
<Window.Resources>
<DataTemplate DataType="{x:Type LargeDataGridViewTest:MainPresenter}">
<DockPanel>
<DataGrid ItemsSource="{Binding Items}"/>
<!--ListBox ItemsSource="{Binding Items}"/-->
<ItemsControl ItemsSource="{Binding Items}"/>
</DockPanel>
</DataTemplate>
</Window.Resources>
<ContentPresenter Content="{Binding}"/>
If instead of the ItemsControl I use the ListBox, the sorting performance is fine. If I use the ListBox but access it's underlying ItemsControl by, e.g., changing the ItemsPanelTemplate, the performance is bad again.
If I take a shallow copy of the list (referencing the same items) and bind the ItemsControl to that instead, the performance is fine again.
Running both the ItemsControl binding that is slow and the fast ListBox binding through EQATEC profiler shows no difference in performance other than the top level app time.
Does anyone have any idea what is happening here?
EDIT
Part of the answer appears to be that ItemsControls aren't virtualized and hence have to draw all their items rather than just the visible ones. In this case, why are all the ItemsControl items redrawn when the DataGrid is sorted (even if the ItemsControl binding mode is OneTime)? And how can I stop this having an impact of the performance of the DataGrid sort?