Интересно почитать… Блог в котором есть много интересной информации…

11 октября 2014

Ограничения WPF DataGrid

Категория: программирование — dmitriano @ 12:13

Как работает стандартный DataGrid

DataGrid это обычный ItemsControl, который биндится к ICollection, подписывается на нотификацию об изменении коллекции INotifyCollectionChaged и на нотификацию об изменении каждого элемента INotifyPropertyChanged, таким образом, если у нас, например, несколько тысяч элементов в коллекции, то соответственно DataGrid подпишется на INotifyPropertyChanged несколько тысяч раз. Если говорить точнее, то DataGrid биндится к ICollectionView, но тем не менее, для DataGrid необходим доступ к  элементу коллекции по индексу (random access). DataGrid по умолчанию использует VirtualizingPanel для реализации UI Virtualization (создаются только видимые ряды), но Data Virtualization не поддерживается, это означает, что все данные должны сидеть в ICollection и биндится будут все элементы, независимо от того видимы они или нет (об этом много статей в интернете). DataGrid поддерживает сортировку и фильтрацию через ICollectionView, что удобно в тривиальных случаях.

Область применения стандартного DataGrid

DataGrid следует использовать для работы с local dataset (working set). То есть если у нас есть база данных на сервере в которой есть таблица с 100 млн. записей, то мы выкачиваем на локальную машину, например 2 тысячи записей выбранных по какому-то критерию и с ними работаем через ICollection. В этом случае DataGrid работает достаточно эффективно.

Ограничения DataGrid

В нетривиальных случаях, если нужно реализовать фильтрацию и сортировку через базу (сервер), а не через локальный ICollection, то DataGrid уже не очень удобен. То есть если при сортировке столбца или фильтрации, мы посылаем SQL запрос на сервер, то когда мы получим recordset от сервера, нужно будет сделать reset всей коллекции (по крайней мере в DataGrid придет нотификация NotifyCollectionChangedAction::Reset и при этом перебиндятся все элементы, съедет текущее выделение SelectedRows).

Если у нас есть real-time данные в виде, например vector<Item> на С++, то чтобы показывать их в DataGrid для них нужно сделать обертку в виде ICollection. В этом случае эксперимент показывает, что если весь массив меняется полностью несколько раз секунду, то приложение наглухо зависает. Судя по всему DataGrid вообще не предназначен для real-time данных.

Задача

Если фильтрация и сортировка данных осуществляется на сервере (или на С++ в native code), то нет необходимости биндить все элементы, которые сидят в ICollection, более того доступ к элементу по индексу тоже не нужен (и соответственно не нужен сам ICollection), достаточно чтобы Data Source выглядел примерно следующим образом:

class MyDataSource<T> 
{ 
    ... 

    T[] GetRange(int starting_index, int count); 

    int Count { get; } 

    void ApplyFilter(...); 

    void Sort(...); 

    ... 
}; 

Причем GetRange() должен вызываться только для видимого диапазона, за счет чего будет реализована динамическая подгрузка данных с сервера при скролировании (эта подгрузка, разумеется, должна быть асинхронной). В интернете есть полу-работающие заплаточные решения такого типа, см http://stackoverflow.com/questions/6592472/using-data-virtualization-the-problem-of-binding-a-property-in-viewmodel-with-s , http://www.zagstudio.com/blog/378 , https://github.com/lordviktor/WPF-DataVirtualization-PoC/blob/master/VirtualizingCollection.cs и т д.

При использовании такого MyDataSource, в случае с vector<Item> на С++ не придется создавать обертку на C# для всего массива, нужно будет только реализовать метод GetRange(), который будет возвращать только обертки для видимых элементов, при этом обертки для элементов можно использовать повторно (это тоже важный момент для оптимизации) что существенно повысит производительно грида.

Линии 3D/Шарики 3D

Комментариев нет »

No comments yet.

RSS feed for comments on this post. TrackBack URL

Leave a comment

SlogPost.ru