Batch Modifications
- 10 minutes to read
Batch modifications are designed to speed up a grid control’s performance by eliminating superfluous updates (visual, re-sorting, selection updates, etc.). The main objective is to update the View only once - after all the necessary changes have been made.
Prevent Excessive Visual Updates
Every time you change a property or call a method that affects a grid’s visual appearance, it is updated to reflect its new state. In some cases, changing a property only affects the corresponding display element, not the entire View, and so only this element is repainted. In most cases however, modifying a property or calling a method affects an entire View, and therefore the View is updated. To update a view, the BaseView.LayoutChanged method is called.
If you perform a sequence of modifications that cause View updates, you may notice that performance suffers, especially when these operations are time-consuming. For instance, deleting hundreds of rows in a View via the ColumnView.DeleteRow method may take a while, because the View is updated after every deletion. However, you can speed up such an operation by preventing unnecessary updates between individual operations. The grid control provides several methods to support such batch modifications.
Before applying a series of changes to a view, you can call the BaseView.BeginUpdate method. This locks the View and prevents subsequent visual updates. After you’ve performed all the necessary operations on a view, call the BaseView.EndUpdate method. This immediately updates the View to reflect all recent changes, as well as re-enables it for future updates.
If changes need to be applied to several Views at the same time, you could use the BaseView.BeginUpdate and BaseView.EndUpdate methods for each of the Views. However, an easier solution is to use the GridControl.BeginUpdate method instead, which locks all open Views in the grid control. Similarly, to unlock all the Views at once call the GridControl.EndUpdate method.
The BeginUpdate
and EndUpdate
methods use an internal counter to implement the appropriate functionality. The counter has an initial value of 0. Each call to the BeginUpdate
method increments this counter by one. Each call to the EndUpdate
method decrements this counter by one and if its new value is zero, the View is updated. Note that each call to BeginUpdate
must be paired with a call to EndUpdate
. If you call BeginUpdate
, but forget to call EndUpdate
afterwards or EndUpdate
isn’t called because an exception occurred, the View will no longer be refreshed. To ensure that EndUpdate
is always called even if an exception occurs, use the try…finally statement.
These points are applied to all the batch modification methods described in this section.
Example
The following example shows how to use the BaseView.BeginUpdate and BaseView.EndUpdate methods to prevent superfluous updates from occurring when deleting records that meet a specific condition.
using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraGrid.Columns;
//...
GridView currentView = gridView1;
GridColumn compColumn = gridView1.Columns["moduleid"];
int compValue = 3;
int rowCount = currentView.DataRowCount;
int rowHandle;
currentView.BeginUpdate();
try {
for (rowHandle = rowCount - 1; rowHandle >= 0; rowHandle--) {
if ((int)currentView.GetRowCellValue(rowHandle, compColumn) == compValue)
currentView.DeleteRow(rowHandle);
}
}
finally {
currentView.EndUpdate();
}
Prevent Excessive Internal Data Updates
The BeginUpdate
and EndUpdate
methods prevent only visual updates. When you change a property or call a method within a BeginUpdate
and EndUpdate
pair, the corresponding actions take effect immediately. But, the results are displayed only after EndUpdate
has been called.
Some operations you may perform force the grid control to reload, re-sort or regroup data. Each of these operations causes an internal data update, and when such operations are performed in a sequence, multiple data updates occur. Excessive data updates cannot be avoided by using the BeginUpdate
and EndUpdate
methods. Instead, the BaseView.BeginDataUpdate and BaseView.EndDataUpdate methods must be used.
These methods improve a control’s performance when a sequence of any of the following operations is performed:
- sorting or grouping by a column;
- modifying the View’s records when data is sorted;
- adding, deleting, or modifying records at the data source level.
If the code that performs a sequence of any of these operations is wrapped with the BeginDataUpdate
and EndDataUpdate
methods, the View will perform only a single data update reflecting all made changes after the EndDataUpdate
method is called.
Use the BeginDataUpdate
and EndDataUpdate
methods in a similar way to the BeginUpdate
and EndUpdate
methods. Each call to the BeginDataUpdate
method must correspond to a call to the EndDataUpdate
method. To ensure that this happens (even if an exception occurs), use the try…finally block.
The BeginDataUpdate
and EndDataUpdate
methods call the BeginUpdate
and EndUpdate
methods, respectively. So, you don’t need to call these methods to prevent superfluous visual updates when using BeginDataUpdate
and EndDataUpdate
methods.
Note
- Do not call the
BeginDataUpdate
andEndDataUpdate
methods in master-detail mode if any detail is currently open, as this can cause some painting artifacts. - Do not expand master rows in code when Grid Control updates are suspended (within the GridControl.BeginUpdate and GridControl.EndUpdate method calls).
The ColumnView.BeginSort and ColumnView.EndSort methods are equivalent to the BeginDataUpdate
and EndDataUpdate
methods.
Example
The following example sorts data by two columns in a Grid View. The code is enclosed within calls to the ColumnView.BeginDataUpdate and BaseView.EndDataUpdate methods. This speeds up performance by sorting the data only once, after the BaseView.EndDataUpdate method is called.
gridView1.BeginDataUpdate();
try {
gridView1.ClearSorting();
gridView1.Columns["Trademark"].SortOrder = DevExpress.Data.ColumnSortOrder.Ascending;
gridView1.Columns["Model"].SortOrder = DevExpress.Data.ColumnSortOrder.Ascending;
}
finally {
gridView1.EndDataUpdate();
}
Preventing Excessive Selection Updates
Views enable you and end-users to select multiple records (rows in Grid Views, cards in Card Views). Refer to the Multiple Row and Cell Selection and End-User Capabilities: Selecting Rows/Cards documents for information on the methods, shortcuts and mouse operations available for working with selections.
The ColumnView.SelectionChanged event occurs every time the selection is changed. For instance, you can write code for an event that fills a list box with the values of the selected records. Every time you add a record to or delete a record from the selection, this event is raised, so your list box is maintained automatically.
Suppose you need to perform several successive selection operations via code (for instance, clear the selection and then call the ColumnView.SelectRow or the ColumnView.SelectRange method). The event will be raised and the View will be updated several times in these cases, depending upon the number of method calls made. To avoid such superfluous updates, use the BaseView.BeginSelection, and BaseView.EndSelection methods. The methods lock and unlock selection updates respectively.
After the BaseView.BeginSelection method is called, the ColumnView.SelectionChanged event does not occur, and the View is not updated when the selection is changed via code. BaseView.EndSelection enables selection updates, fires the ColumnView.SelectionChanged event and updates the View to reflect all the recent selection changes.
So, you can use these methods to prevent the display from flickering when selecting multiple rows via code and when performing time-consuming operations or operations that require screen updates via the ColumnView.SelectionChanged event.
Using the BaseView.BeginSelection and BaseView.EndSelection methods is similar to using the BeginUpdate
and EndUpdate
methods. You must always ensure that each call to BaseView.BeginSelection is followed by a corresponding call to the BaseView.EndSelection method. For this purpose, we advise you to use a try…finally statement. Nesting method calls are also supported.
The BaseView.BeginSelection method only locks selection related updates and does not lock any other updates. So if you need to prevent visual updates, you still need to use the BaseView.BeginUpdate method.
The following code demonstrates how to prevent selection updates when selecting rows that meet a specific condition.
using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraGrid.Columns;
//...
GridView currentView = advBandedGridView1;
GridColumn compColumn = currentView.Columns["Discontinued"];
currentView.OptionsSelection.MultiSelect = true;
currentView.ExpandAllGroups();
bool compValue = true;
currentView.BeginSelection();
try {
currentView.ClearSelection();
int rowHandle;
for (rowHandle = 0; rowHandle < currentView.DataRowCount; rowHandle ++)
if ((bool)currentView.GetRowCellValue(rowHandle, compColumn) == compValue)
currentView.SelectRow(rowHandle);
}
finally {
currentView.EndSelection();
}
In some cases, you can call the BaseView.CancelSelection method instead of the BaseView.EndSelection method. This method enables selection updates, but it does not fire the ColumnView.SelectionChanged event, and therefore does not repaint the View. For instance, if you call BaseView.BeginSelection, but don’t change the selection, you can use BaseView.CancelSelection rather then BaseView.EndSelection to avoid the unnecessary final update.
Preventing Excessive Collection Updates
The grid control provides methods to prevent excessive updates when manipulating summary items and style conditions that are stored in corresponding collections.
Summary items are supported by the GridSummaryItemCollection class. The GridSummaryItemCollection.BeginUpdate and GridSummaryItemCollection.EndUpdate methods enable you to perform batch modifications. Use these methods in a similar way to the other BeginUpdate
and EndUpdate
methods. Just enclose the code that modifies the summary collection (adds or deletes individual summaries, changes summary settings), within the GridSummaryItemCollection.BeginUpdate and GridSummaryItemCollection.EndUpdate methods, and this will prevent superfluous summary re-calculations and View updates. Summaries will be re-calculated only once - after the GridSummaryItemCollection.EndUpdate method has been called.
The following code demonstrates how to prevent needless summary recalculations when adding two total summaries.
using DevExpress.XtraGrid;
using DevExpress.XtraGrid.Views.Grid;
//...
GridView currentView = advBandedGridView1;
GridSummaryItemCollection coll = currentView.Columns[0].SummaryItem.Collection;
coll.BeginUpdate();
try {
GridSummaryItem sumItem = currentView.Columns["Price"].SummaryItem;
sumItem.SummaryType = DevExpress.Data.SummaryItemType.Max;
sumItem.FieldName = "Price";
sumItem.DisplayFormat = "Max: {0:c0}";
sumItem = currentView.Columns["Model"].SummaryItem;
sumItem.SummaryType = DevExpress.Data.SummaryItemType.Count;
sumItem.FieldName = "Model";
sumItem.DisplayFormat = "Records: {0}";
}
finally {
coll.EndUpdate();
}
Note that we use a try…finally block to ensure that the GridSummaryItemCollection.EndUpdate method is always called after the GridSummaryItemCollection.BeginUpdate call.
The GridSummaryItemCollection class provides the GridSummaryItemCollection.CancelUpdate method, which you can use in some cases instead of the GridSummaryItemCollection.EndUpdate method. This method enables summary collection updates, but does not force an immediate summary recalculation and does not update the View.
For more information on summaries, refer to the Summaries document.
Style conditions are represented by the StyleFormatConditionCollection class. This class also provides the FormatConditionCollectionBase.BeginUpdate and FormatConditionCollectionBase.EndUpdate methods, which you can use to enclose the code that changes the collection, and so prevent unnecessary View updates. Use these methods in a similar way to the other batch modification methods.