У нас есть сетка данных в окне, которая связана с коллекцией объектов.У нас очень плохие показатели в этом окне;загрузка может занять до 20 секунд, а затем 5-7 секунд каждый раз, когда вы «прокручиваете» сетку данных.Это всего 12 предметов.Когда мы исследовали, казалось, что основной причиной замедления были добытчики имущества;некоторые из наших получателей вызывались свыше 20000 раз (это 1666.667 раз за объект)!Приборы показали, что наши геттеры не были особенно медленными;самый медленный занял 0,002 секунды.К сожалению, когда вы умножаете 0,0002 * 20k, вы легко получаете задержку, которую мы испытываем.
Мы сели и создали пример проекта с проверкой проблемы.В этом проекте мы создали очень простой класс, очень простую модель представления и очень простое окно.Мы добавили некоторый код, чтобы попытаться наблюдать за проблемой.Хотя мы не видим ничего похожего на масштабы проблем, которые мы видели ранее, это гораздо более простой экран;что более тревожно для нас, мы увидели доказательства того, что мы считаем «чрезмерным» использованием приобретателей имущества.В этом примере, когда вы запускаете экран, они начинаются с 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();
}
}
}
***** КЛАСС ВХОДА *****
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;
}
}
***** КЛАСС МОДЕЛИ ВИДА НА ВХОД *****
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;
}
}
}