У нас есть сетка данных в окне, которое связано с набором объектов. У нас очень плохое представление об этом окне; загрузка может занять до 20 секунд, а затем 5-7 секунд при прокрутке сетки данных. Это до 12 штук. Когда мы исследовали, казалось, что основной причиной замедления были имущественные геттеры; некоторые из наших получателей были вызваны свыше 20 000 раз (это 1666,667 раза за объект)! Инструментарий показал, что наши геттеры не были особенно slow; самый медленный - 0,002 секунды. К сожалению, когда вы умножаете 0.0002 * 20k, вы легко получаете задержку, с которой мы сталкиваемся.DataGrid избыточное свойство привязки данных Получить вызовы
Мы сели и создали пробный проект с доказательством проблемы. В этом проекте мы создали мертво-простой класс, простую модель View Model и очень простое окно. Мы добавили некоторый код, чтобы попытаться увидеть проблему. Хотя мы ничего не видим вблизи масштабов проблем, которые мы видели ранее, это гораздо более простой экран; более тревожно для нас, мы видели доказательства того, что мы будем считать «чрезмерным» использованием имущих геттеров. В этом примере, когда вы запускаете экран, они начинаются с 1; когда вы прокручиваете вниз, а затем выполняете резервное копирование, некоторые из них теперь до 5 или 6; прокрутка назад, и вы увидите некоторые из нижних до 9 или около того.
В случае этого доказательства концепции это не проблема; но наши фактические объекты намного сложнее, и мы не можем позволить себе 40-секундные задержки для доступа к собственности 20 000 раз! Кто-нибудь знает, что здесь происходит? Как я могу заставить сетку опробовать мои объекты менее агрессивно? Мы используем WPF-Toolkit DataGrid и .NET версии 3.5. Пример кода для PoC ниже:
***** ОКНО КОД *****
<Window x:Class="PocApp.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfToolkit="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
Title="Window1" Height="200" Width="200">
<Grid>
<WpfToolkit:DataGrid ItemsSource="{Binding Path=MyEntries}">
</WpfToolkit:DataGrid>
</Grid>
</Window>
***** ОКНО КОД-ЗА *****
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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;
namespace PocApp
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
this.DataContext = new EntryViewModel();
}
}
}
***** ENTRY КЛАСС *****
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PocApp
{
public class Entry
{
public Entry(string first, string last)
{
FirstName = first;
LastName = last;
}
public string FirstName
{
get
{
firstCall++;
System.Console.WriteLine("FirstName Call:" + firstCall);
return _firstname;
}
set
{
_firstname = value;
}
}
public int FirstNameCallCount
{
get
{
return firstCall;
}
}
public string LastName
{
get
{
lastCall++;
System.Console.WriteLine("LastName Call:" + lastCall);
return _lastname;
}
set
{
_lastname = value;
}
}
public int LastNameCallCount
{
get
{
return lastCall;
}
}
private string _firstname,_lastname;
private int firstCall,lastCall = 0;
}
}
***** ENTRY Модельное КЛАСС *****
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
namespace PocApp
{
public class EntryViewModel
{
public EntryViewModel()
{
List<Entry> myCoolEntries = new List<Entry>()
{
new Entry("A","A1"),
new Entry("B","B1"),
new Entry("C","C1"),
new Entry("D","D1"),
new Entry("E","E1"),
new Entry("F","F1"),
new Entry("G","G1"),
new Entry("H","H1"),
new Entry("I","I1"),
new Entry("J","J1"),
new Entry("K","K1"),
new Entry("L","L1"),
new Entry("M","M1"),
new Entry("N","N1"),
new Entry("O","O1"),
new Entry("P","P1"),
new Entry("Q","Q1"),
};
MyEntries = (CollectionView)CollectionViewSource.GetDefaultView(myCoolEntries);
}
public CollectionView MyEntries
{
get;
private set;
}
}
}
Мы выяснили проблему. В нашей реальной реализации объекты, которые привязаны, являются обертками для объектов DataRow. Они полагаются на событие DataTable.RowChanged для обработки NotifyPropertyChanged для них. Оказывается, когда эти строки прокручиваются и не отображаются, событие RowChanged запускается несколько раз. Отключение этого события нашло общее количество вызовов от 200 к + примерно до 50 или около того. Спасибо за отзыв о NotifyPropertyChanged. – GWLlosa