Skip to main content
A newer version of this page is available. .

Frequent Update Performance Enhancement

  • 5 minutes to read

Optimized Summary Calculation Mode

Starting with v15.2, the GridControl featured a special mode allowing you to update data summaries without recalculating them for all records. Instead, the grid calculates delta values for changed records and updates summaries according to these values. As a result, the time spent on updating summary values does not depend on the number of records.

To enable this mode, set the grid’s GridControl.OptimizeSummaryCalculation property to true. The grid should be bound to an ObservableCollection whose items implement the INotifyPropertyChanged and INotifyPropertyChanging interfaces. Calculation of custom summaries and summaries for unbound columns cannot be optimized.

ChunkList Overview

Starting with v15.2, the DevExpress WPF Suite featured a new collection type ChunkList<T>, which is designed to improve performance when handling updates of large collections.

Note

Using the ChunkList<T> provides significant performance improvements in applications that handle a large and frequently updated data source. However, operations that iterate over the elements of the data source (e.g., sorting, filtering, summary calculation) are executed slowly in comparison. Using the ChunkList<T> in common scenarios is not recommended.

Items within the ChunkList<T> collection are broken up in relatively small sublists of a fixed size - chunks. Thus, each element can be accessed by its chunk index and index within a chunk. This structure provides much better performance when executing the IndexOf, Insert and Remove data operations compared to a regular list.

The IndexOf operation is called each time the PropertyChanged event fires for an object in a collection to determine the object’s position on the list. In a standard collection, it is necessary to iterate through the entire list to find the object index. In ChunkList<T>, the object’s chunk index is already known, and you are only required to find the object’s index within a chunk.

When the Insert or Remove operations are performed in a standard collection, the collection has to shift all the items following the inserted/removed item. In ChunkList<T>, items will only be shifted in a chunk where the item was inserted or removed, while other chunks stay intact.

The table below illustrates the difference in performance between BindingList and ChunkList<T>.

Scenario (1,000,000 items)

BindingList

Standalone

ChunkList

Standalone

BindingList

Bound to GridControl

ChunkList

Bound to GridControl

Creation time

1016

1171

1422

2016

Insert 10000 items

6422

250

7765

469

Remove 10000 items

9700

219

8400

438

Update 10000 items

58700

156

59328

250

Full iteration

47

328

Memory used (MB)

59

90

Sort string property

7485

8187

Sort int property

2465

3313

Implementing ChunkList

When creating a ChunkList<T>, you need to specify the approximate size of the collection using the capacity parameter of the ChunkList<T> constructor. The chunk size is calculated as the square root of the capacity value. You can also use the constructor’s chunkSize parameter instead to explicitly set the chunk size.

There are two ways to enable the ChunkList<T> to determine the data object’s chunk index.

  • Implement the IChunkListObject.ChunkObject property of the IChunkListObject interface in your data objects, so the chunk index is stored in a field at the object level.

    Pros: data source is generated faster and consumes less memory.

    Cons: this method requires data object modification.

    See the example below.

    public class DataObject : IChunkListObject {
            public int NumericField { get; set; }
            public string StringField { get; set; }
            public object ChunkObject { get; set; }
        }
        public class DataSource {
            public ChunkList<DataObject> Data { get; set; }
            public DataSource() {
                Data = new ChunkList<DataObject>(capacity: 1000000);
                for (int i = 0; i < 1000000; i++) {
                    Data.Add(new DataObject());
                }
            }
        }
    
  • Set the useChunksCache parameter of the ChunkList<T> constructor to true to create a hash table that stores chunk indexes for collection items.

    Pros: this method does not require data object modification.

    Cons: the hash table requires additional memory.

    See the example below.

    public class DataObject {
            public int NumericField { get; set; }
            public string StringField { get; set; }
        }
        public class DataSource {
            public ChunkList<DataObject> Data { get; set; }
            public DataSource() {
                Data = new ChunkList<DataObject>(capacity: 1000000, useChunksCache: true);
                for (int i = 0; i < 1000000; i++) {
                    Data.Add(new DataObject());
                }
            }
        }
    

    You can also enable each chunk to listen to PropertyChanged events separately by setting the supportPropertyChanged parameter to true. In this case, there is no need to determine the chunk index to find the item position in the list, so you can disable creating a hash table by setting the useChunksCache parameter to false. However, the IndexOf operation called in runtime will not be optimized.

    See the example below.

    public class DataObject : INotifyPropertyChanged {
            private int numericField;
            private string stringField;
            public int NumericField {
                get { return numericField; }
                set {
                    numericField = value;
                    OnPropertyChanged("NumericField");
                }
            }
            public string StringField {
                get { return stringField; }
                set {
                    stringField = value;
                    OnPropertyChanged("StringField");
                }
            }
            public event PropertyChangedEventHandler PropertyChanged;
            protected virtual void OnPropertyChanged(string propertyName) {
                var handler = PropertyChanged;
                if (handler != null)
                    handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public class DataSource {
            public ChunkList<DataObject> Data { get; set; }
            public DataSource() {
                Data = new ChunkList<DataObject>(chunkSize: 1000, supportPropertyChanged: true);
                for (int i = 0; i < 1000000; i++) {
                    Data.Add(new DataObject());
                }
            }
        }