DataGrid Избыточное свойство привязки данных Получить вызовы - PullRequest
0 голосов
/ 17 сентября 2010

У нас есть сетка данных в окне, которая связана с коллекцией объектов.У нас очень плохие показатели в этом окне;загрузка может занять до 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;
        }
    }
}

1 Ответ

2 голосов
/ 17 сентября 2010

Числа, которые вы видите в доказательстве концепции, на самом деле нормальные. Они являются результатом виртуализации строк внутри сетки данных; когда элемент прокручивается вне поля зрения, строка контейнера повторно используется для отображения вновь введенного элемента, таким образом сохраняя низкое использование памяти по отношению к фактическим визуальным элементам управления, созданным и управляемым. Отображение другого элемента означает запрос связанных свойств.

Обычно я не думаю, что это будет проблемой; Я работал с довольно сложными бизнес-объектами и отображал довольно много данных в сетке данных без проблем, о которых вы упомянули. Я бы посоветовал взглянуть на любые стили, применяемые к сетке данных, так как они могут мешать виртуализации строк; Кроме того, методы получения свойств, выполнение которых занимает 2 миллисекунды, - это не то, что я бы назвал быстрым:)

Редактировать: на самом деле, избежать дополнительных вызовов к получателям свойств можно было бы только отключив виртуализацию, которая создала бы огромные проблемы с производительностью - как тонны потраченной памяти, так и производительность прокрутки при даже небольшой '(тысячи) количество строк в сетке данных. Тем не менее, это единственное, что я могу сказать без дополнительной информации. Если это вообще возможно, попробуйте выполнить пошаговое выполнение кода при вызове геттеров и более точно определить источник и время большинства вызовов. Если проблемы возникают при прокрутке, то ваши сущности действительно невероятно сложны, и я подвергаю сомнению ценность отображения их в таблице данных таким образом.

Другое редактирование: я перечитал вопрос более внимательно и заметил, что вы сказали 12 пунктов ?! Извините, но теперь я совершенно непреклонен, говоря, что в этом не следует винить сетку данных, если только у ваших объектов нет тысяч свойств, все они привязаны к столбцам в сетке данных, что, я сомневаюсь, вообще возможно. Пожалуйста, ознакомьтесь с остальной частью кода и стилей и постарайтесь определить возможные проблемные области, о которых мы могли бы посоветовать ... не знаю, что еще сказать. Также убедитесь, что сущности не вызывают ненужные события NotifyPropertyChanged, так как это приведет к повторному запросу свойства связанными элементами управления.

...