KB Article KA18635
Visible to All Users

How to avoid problems with the DXGrid virtualization mechanism

Description:

The DXGrid utilizes the virtualization mechanism to improve its performance. Virtualization reuses row, cell, and column visual elements, and changes their properties and data context. Virtualization occurs when a visual element is moved outside screen bounds (e.g., when the grid is scrolled or a TreeList node is expanded). Since visual objects are not recreated completely, there may be certain issues; for example, when trying to change a particular cell appearance. How to solve these issues?

Answer:

Though all issues with virtualization are caused by the fact that grid objects are reused, these issues can occur in different use cases, so the best way to describe the virtualization concept is to list the most common use cases (incorrect ones) and demonstrate a proper way of dealing with them.

1. Incorrect bindings.

The data context of cell and row elements (RowData, EditGridCellData, etc.) is not completely recreated, but is only modified according to a row and cell that these elements currently represent. Therefore, bindings to this exact context will not be updated properly.

Let's take a look at an example. Assume you wish to color blank cells in the grid so that it becomes easier for the user to find them. To implement this, you create a custom CellStyle as follows:

XAML
INCORRECT BINDING EXAMPLE <Style BasedOn="{StaticResource {dxgt:GridRowThemeKey ResourceKey=CellStyle}}" TargetType="dxg:CellContentPresenter"> <Setter Property="Background" Value="{Binding Converter={StaticResource Converter}}"/> </Style>

Here, a converter is used to check a cell value and return a certain color depending on the check result. However, converter methods will be called neither on the cell value changing nor when the scrolling is performed. The problem here is that the EditGridCellData object itself is not changed in these situations. So, the binding expression for the Background property will not be re-evaluated. To solve this issue, set the binding property path directly to the cell value:

XAML
CORRECT BINDING EXAMPLE <Style BasedOn="{StaticResource {dxgt:GridRowThemeKey ResourceKey=CellStyle}}" TargetType="dxg:CellContentPresenter"> <Setter Property="Background" Value="{Binding Value, Converter={StaticResource Converter}}"/> </Style>

The above example is simple, as it only uses a cell value to calculate cell color. Sometimes it is necessary to use the whole EditGridCellData object to check a cell for multiple conditions (e.g., to return a different color for a focused or selected cell). In this case, you can use MultiBinding and even pass the EditGridCellData object to the converter, but it is also necessary to add bindings to all properties whose changing should trigger the converter call:

XAML
<Style BasedOn="{StaticResource {dxgt:GridRowThemeKey ResourceKey=CellStyle}}" TargetType="dxg:CellContentPresenter"> <Setter Property="Background"> <Setter.Value> <MultiBinding Converter="{StaticResource MultiConverter}"> <Binding /> <Binding Path="Value" /> <Binding Path="IsSelected" /> <Binding Path="RowData.IsFocused" /> </MultiBinding> </Setter.Value> </Setter> </Style>

The same is true for other bindings that use the row and cell data context (bindings inside the CellTemplate, DisplayTemplate, EditTemplate, RowStyle, etc.).

2. Manual modifications of grid visual elements.

In our GridControl, you can retrieve grid visual elements that are used to represent a cell via the GetRowElement… and GetCellElement… methods. However, it is not recommended to use these elements to change cell appearance since modifications made for an element that represent a certain cell will remain even after this element is reused. The code operation below will cause virtualization issues and should be done in an appropriate style or template:

C#
GridCellContentPresenter element = tableView.GetCellElementByRowHandleAndColumn(rowHandle, gridControl.Columns["FieldName"]) as GridCellContentPresenter; element.Background = new SolidColorBrush(Colors.Red);

3. The use of custom attached properties.

Sometimes, if data placed in the EditGridCellData object is not enough to calculate the value of the property that should be changed in style (e.g., the cell background), it makes sense to attach a custom property to the cell and change this property when necessary (e.g., in the CellValueChanged method).

However, the value of the property attached to a row or cell element will be used for multiple rows and cells during the grid virtualization.
In this case, there are two approaches to overcome the situation: attach your custom property to the RowState object (that can be obtained from the RowData field) or use Unbound Columns instead of attached properties. In the second approach, you can get an unbound column value in xaml using RowTypeDescriptor that is the data context for the RowData object and is stored in the Data field of the EditGridCellData object. For example:

XAML
<Style BasedOn="{StaticResource {dxgt:GridRowThemeKey ResourceKey=CellStyle}}" TargetType="dxg:CellContentPresenter"> <Setter Property="Background" Value="{Binding Data.UnboundField, Converter={StaticResource Converter}}"/> </Style> ... <Style BasedOn="{StaticResource {dxgt:GridRowThemeKey ResourceKey=RowStyle}}" TargetType="{x:Type dxg:GridRowContent}"> <Setter Property="Background" Value="{Binding DataContext.UnboundField, Converter={StaticResource Converter}}" /> </Style>

4. Applying animation to rows and cells.

Due to virtualization specifics, attaching animation to row and cell elements will also produce issues on scrolling. The only way to avoid these issues is to create an unbound column to store custom objects with animation attached and bind element properties to these objects in style. This approach is demonstrated in the following example: E841: How to highlight modified rows.

5. Handling value changed events for cell editors.

Cell editors are not recreated during the virtualization process as well, so their values are changed not only when the user interacts with them or the data source is changed, but also when the grid is being scrolled. Therefore, instead of handling an editor's value changed events, it is recommended to use CellValueChanging/CellValueChanged.

Appendix.

Since the grid virtualization occurs mostly when the grid is being scrolled, there can be two types of its virtualization: horizontal and vertical. The difference between them is that during the horizontal virtualization, column objects are also recreated.

There can be certain issues specific to the horizontal virtualization. For example, when you scroll through columns with different types and type-dependent editors, and a cell value is bound to an editor manually, a new value may be passed before the editor is changed, which will result in a format exception. To solve such issues, disable the horizontal virtualization by setting the AllowHorizontalScrollingVirtualization property to false.
As for the vertical scrolling virtualization, it cannot be disabled either directly or by using ScrollViewer properties. However, understanding the specifics of the DXGrid virtualization concept, you will unlikely face any problems with it and will benefit from the performance increase provided.

Show previous comments (5)
Alex Chuev (DevExpress) 10 years ago

    Hi,

    I've created a separate ticket on your behalf: T218201 - How to implement cell animation in the grid and make sure that there are no virtualization issues. Let's discuss your requirements there.

    Thanks,
    Alex

      Hi,

      We have a weird issue with the Virtualization.
      We have several columns, half with CellTemplate = cellTemplate1 and the rest with cellTemplate2. Only columns with cellTemplate2 has the converter.

      When we move horizentally to the end (to columns with cellTemplate2) and go back the columns that are using the cellTemplate1 we get to the converter of cellTemplate2 with column that is using cellTemplate1 (which doesn't have a converter at all).

      If we set the virtualization to false everything works. We use the virtualization as true since it works very good with performance.

      What is going on here, could be that when you change the columns data, you forget to set the cellTemplate?

      Best regards,
      Chen

      DevExpress Support Team 9 years ago

        Hi Chen,

        To process your recent post more efficiently, I created a separate ticket on your behalf: T348355: GridControl doesn't correctly apply cell templates when scrolling horizontally. This ticket is currently in our processing queue. Our team will address it as soon as we have any updates.

        Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

        Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.