2010-09-16 4 views
0

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

ответ

2

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

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

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

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

+0

Мы выяснили проблему. В нашей реальной реализации объекты, которые привязаны, являются обертками для объектов DataRow. Они полагаются на событие DataTable.RowChanged для обработки NotifyPropertyChanged для них. Оказывается, когда эти строки прокручиваются и не отображаются, событие RowChanged запускается несколько раз. Отключение этого события нашло общее количество вызовов от 200 к + примерно до 50 или около того. Спасибо за отзыв о NotifyPropertyChanged. – GWLlosa

Смежные вопросы