В частности, это продолжение этого вопроса Производительность фильтра DataGrid , но есть еще много похожих вопросов, касающихся производительности WPF DataGrid в StackOverflow.
После большого количества профилирования и изучения исходного кода .NET я понял, что многие проблемы с производительностью, такие как фильтрация и сортировка , сводятся к одной проблеме: A CollectionView Событие .Reset не перезапускает контейнеры (как прокрутка).
Я имею в виду, что вместо назначения существующим строкам нового текста данных все строки удаляются из визуального дерева, создаются и добавляются новые строки, и выполняется цикл компоновки (измерение и аранжировка).
Итак, главный вопрос: Кому-нибудь удалось успешно обойти это? Например. путем ручного манипулирования ItemContainerGenerator или создания собственной версии DataGridRowsPresenter?
Так что это суть моего подхода до сих пор.
public class CollectionViewEx
{
public event EventHandler Refresh;
public override void Refresh()
{
Refresh?.Invoke(this, EventArgs.Empty);
}
}
public class DataGridEx : DataGrid
{
protected override OnItemsSourceChanged(IEnumerable oldSource, IEnumerable newSource)
{
if (newSource is CollectionViewEx cvx)
{
cvx.Refresh += (o,a) => OnViewRefreshing;
}
}
private void OnViewRefreshing()
{
RowsPresenter.Refresh();
}
}
public class DataGridRowsPresenterEx : DataGridRowsPresenter
{
public void Refresh()
{
var generator = (IRecyclingItemContainerGenerator)ItemContainerGenerator;
generator.Recycle(new GeneratorPosition(0, 0), ???);
RemoveInternalChildRange(0, VisualChildrenCount);
using (generator.StartAt(new GeneratorPosition(-1, 0), GeneratorDirection.Forward))
{
UIElement child;
bool isNewlyRealised = false;
while ((child = generator.GenerateNext(out isNewlyRealised) as UIElement) != null)
{
AddInternalChild(child);
generator.PrepareItemContainer(child);
}
}
}
}
Но результаты очень запутанные - очевидно, потому что я не совсем понимаю, как работать с ICG.
Я просмотрел исходный код .net, чтобы увидеть их реализации (при добавлении / удалении / замене элементов), а также нашел несколько онлайн-ресурсов о том, как создать новую виртуализированную панель (например, virtualizingwrappanel), но ни один из них не касается эта конкретная проблема, где мы хотим повторно использовать все существующие контейнеры для нового набора элементов .
Итак, второстепенный вопрос: Может кто-нибудь объяснить, возможен ли такой подход? Как бы я это сделал?