Why sorting using CollectionViewSource.SortDescriptions is slow?
This is the default sort method when you click on a column he开发者_Python百科ader in a DataGrid
. When the underlying list contains 100,000 items, it takes about 20 seconds to refresh the view. Same delay can be observed when setting SortDescription
s on a CollectionView
.
Sorting by using ListCollectionView.CustomSort
or by sorting and re-assinging the list works almost instantly.
Why is this delay? Is this just a "reflection tax" on the bound properties?
You are right, this is a reflection tax. I looked very closely on DataGrid performance some time ago, and reflection was a bottle neck here. No matter how fast is sorting algorithm, they don't cache property's value between two comparisons. So, even if you have n*ln(n) comparisons, with n == 100 000 you'll get ~1 000 000 operations. Each operand uses reflection to get value, so you have 2 000 000 calls to reflection in tax :) ... ListCollectionView.CustomSort
is ideal solution here.
PS: At the end of the day, we wrote ListView-based grid, because we were not satisfied with DataGrid rendering performance too... But that's another story :)
The best performance tweak for filtering, was toggling DataGridRow Visibility. It made magnitude of difference!
1.Add IsVisible property to the Collection Item that you Bind the DataGrid's ItemSource to.
private bool _isVisible = true;
public bool IsVisible
{
get { return _isVisible; }
set
{
if (_isVisible == value)
return;
_isVisible = value;
RaisePropertyChanged(()=>IsVisible);
}
}
2.Trigger the Visibility of DataGridRow by binding it to your IsVisible property:
<DataGrid.ItemContainerStyle>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="Visibility"
Value="{Binding Path=IsVisible,
Converter={StaticResource BoolToVisibility}}"/>
</Style>
</DataGrid.ItemContainerStyle>
3.Well, you gotta set the IsVisible somewhere I guess too, like in your ViewModel. Here's just a sample of what I am doing (just copy/paste job) - basically setting IsVisible to true or false based on some criteria in my other ViewModel:
FilterViewModel.OnFilter += (s, a) =>
{
foreach (Row row in ViewModel.Rows)
row.IsVisible = !FilterViewModel.FilteringItems.Any(item =>
item.IsSelected && item.Name == row.Name);
};
精彩评论