Log In
Home
Support
Demos
Documentation
Blogs
Training
Webinars
[Expand]General Information
[Collapse]WinForms Controls
  Prerequisites
 [Expand]What's Installed
 [Expand]Build an Application
 [Collapse]Controls and Libraries
  [Expand]Forms and User Controls
  [Expand]Messages, Notifications and Dialogs
  [Expand]Editors and Simple Controls
  [Expand]Ribbon, Bars and Menu
  [Expand]Application UI Manager
  [Expand]Docking Library
  [Collapse]Data Grid
   [Collapse]Getting Started
    [Collapse]Walkthroughs
     [Expand]Appearance and Conditional Formatting
     [Expand]Data Editing
     [Expand]Hit Information
     [Expand]Data Binding and Working with Columns
     [Collapse]Grid View - Columns, Rows and Cells
       Tutorial: Column Resizing
       Tutorial: Best Fit Option
       Tutorial: Auto Width Mode
       Tutorial: Fixed Columns
       Tutorial: Column Reordering
       Tutorial: Column Visibility
       Tutorial: Column Chooser API
       Tutorial: Auto Row Height
       Tutorial: Cell Merging
       Tutorial: Identifying Rows
       Tutorial: Row Height and Layout Basics
     [Expand]Banded Views
     [Expand]WinExplorer View
     [Expand]Tile View
     [Expand]Grouping
     [Expand]Filter and Search
     [Expand]Sorting
     [Expand]Summaries
     [Expand]Split Presentation
     [Expand]Row Preview Sections
     Data Grid and Views
   [Expand]Data Binding
   [Expand]Views
   [Expand]Data Editing and Validation
   [Expand]Grouping
   [Expand]Sorting
   [Expand]Filter and Search
   [Expand]Summaries
   [Expand]Focus and Selection Handling
    Formatting Cell Values
   [Expand]Master-Detail Relationships
   [Expand]Asynchronous Image Load
   [Expand]Export and Printing
   [Expand]Appearance and Conditional Formatting
    Split Presentation
    Row Preview Sections
    Scrolling
   [Expand]Batch Modifications
   [Expand]Hit Information
    Hints
   [Expand]Popup Menus
   [Expand]Saving and Restoring Layouts
   [Expand]Visual Elements
   [Expand]Design-Time Features
   [Expand]Examples
   [Expand]End-User Capabilities
    Included Components
  [Expand]Vertical Grid
  [Expand]Pivot Grid
  [Expand]Tree List
  [Expand]Chart Control
  [Expand]Diagrams
  [Expand]Gauges
  [Expand]Map Control
  [Expand]Scheduler
  [Expand]Spreadsheet
  [Expand]Rich Text Editor
  [Expand]Spell Checker
  [Expand]Form Layout Managers
  [Expand]Navigation Controls
  [Expand]Printing-Exporting
  [Expand]PDF Viewer
   Reporting
  [Expand]Snap
  [Expand]TreeMap Control
 [Expand]Common Features
  Get More Help
 [Expand]API Reference
[Expand]ASP.NET Controls and MVC Extensions
[Expand]ASP.NET Bootstrap Controls
[Expand]ASP.NET Core Bootstrap Controls
[Expand]WPF Controls
[Expand]Xamarin Controls
[Expand]Windows 10 App Controls
[Expand]Document Server
[Expand]Reporting
[Expand]Report Server
[Expand]Dashboard
[Expand]eXpressApp Framework
[Expand]CodeRush
[Expand]CodeRush Classic
[Expand]Cross-Platform Core Libraries
[Expand]Tools and Utilities
 End-User Documentation

Tutorial: Identifying Rows

This walkthrough is a transcript of the Identifying Rows video available on the DevExpress YouTube Channel.

In this tutorial, you'll learn about the ways grid Views identify their rows.

  • Data source row indexes
  • Row handles
  • Visible indexes

Expanded Overview

Data source indexes refer to records in the bound list. You will use them for data editing. As you can expect each data row has a unique index, while group rows simply refer to the first available data row, and service rows return negative values.

Row handles are used by the grid View to identify rows of any type. Group rows have consecutive negative indexes, service rows have pre-defined values and data rows have positive indexes.

Finally, visible indexes enumerate all rows in the order they are visible on screen. These identifiers are mainly used to implement row navigation.

Now take a closer look at when to use each type of row identifiers and how they differ from one another.

Expanded Row Identifiers in Plain Data

If you have plain data displayed by the grid, then these three identifiers are usually the same in each row. All of them are row indexes that start with 0.

Expanded Differences Between Row Identifiers when Sorting and Filtering Data

Sorting Data

Sorting data is one way to see the difference between these identifiers. The order of records has changed, and the data source indexes followed. Same rows are identified by the same data source indexes but the order is now different. On the other hand, row handles and visible indexes are still consecutive integers starting with 0 and they match each other in each row.

Filtering Data

A similar effect is achieved when you filter rows. Data is reloaded, row structure is being re-built, and so visible indexes and row handles are updated to reflect the new structure, while data source indexes follow their corresponding rows.

Incorrect Using Row Handles

An important takeaway is that row handles and visible indexes change in response to user actions. Create a simple example to illustrate this point. The Save Index button in the Ribbon control will save the currently focused row's handle. For this purpose, declare an integer savedRowHandle field and assign the grid View's ColumnView.FocusedRowHandle property value to it.

There's also the Change Value button. Its Click event handler uses the ColumnView.SetRowCellValue method to set the Name column cell to an empty string within the saved row.

Run the application and first focus the row with Audi A6. Click the Save Index button, then move focus away and finally click the Change Value button. As expected, the cell in the saved row has been changed.

Re-start the application. Now, first sort the Name column, then locate the row showing Audi A6. Save the row's handle, which is now 2 - using the Save Index button. Then, clear sorting and notice how the row's handle has changed. So, if you press Change Value, it will not change in the Audi A6 row that was saved.

Using Data Source Indexes Instead of Row Handles

To fix this, you need to modify the code so that it stores data source indexes instead of row handles. Then, in the Change Value handler, convert the stored index into a row handle and only then apply the change.

Run the application to see that the code works as expected now even when using data shaping operations such as sorting or filtering.

Expanded Differences Between Row Identifiers When Grouping Data

Differences Between Row Handles and Data Source Indexes

Next see what happens when you group data. One of the key differences between row handles and data source indexes is that row handles for group rows are negative integers. There are obviously no data source indexes for group rows, because they don't exist in the data source. So the values shown in group rows are indexes of the first data row within the group. One more thing worth noting is that row handles for data rows are always non-negative integers.

Iterating Through Rows Using Row Handles

If you want to iterate through all rows in the grid control's memory, you can simply enumerate row handles from 0 to the View's BaseView.DataRowCount property.

Take a look the Clear Name button's Click event handler that does exactly this to clear values in the Name column for all currently loaded rows. The handler code is wrapped into the BaseView.BeginUpdate and BaseView.EndUpdate method calls to avoid multiple updates to the View. It starts with the row handle equal to 0 and then enumerates all integers up to the BaseView.DataRowCount property value. The loop body calls the ColumnView.SetRowCellValue method to clear the value in the Name column.

Run the application. First filter the records to display only Audis. Click the button and see the names cleared. Now remove filtering and group data by Make. You'll see the Name column has been cleared in the Audi group, but other makes still have the data.

So only those rows that matched the filter criteria were loaded into the memory. If you press the Clear Name button now, the change will affect all rows – in expanded or collapsed groups.

Differences Between Row Handles and Visible Indexes

The grouped View also reveals an important difference between row handles and visible indexes. First, visible indexes still start with 0 and the value is incremented with each visible row – be it a group row or a data row. Secondly, you'll notice that row handles are already assigned to all rows loaded into the memory, including those in collapsed groups. Expand and collapse operations on group rows don't affect row handles. Visible indexes, on the other hand, will be recalculated with each expanded state change to account for rows that have become visible or hidden.

Using Visible Indexes

To illustrate the usage of visible indexes, implement a button that navigates to the next visible row in the View – an alternative to pressing the DOWN key. The handler first determines the focused row's visible index using the GridView.GetVisibleIndex method that takes a row handle as a parameter. Next the code increments the obtained visible index, and, finally, converts it back to a row handle value using the GridView.GetVisibleRowHandle method and sets the focus using this newly obtained handle.

Run the application. You'll see that the button works in both plain and grouped views.

Expanded Special Row Handles

One last thing worth mentioning in this tutorial is that special types of rows, such as the New Item Row, are assigned pre-defined row handle values.

To see how you can use these predefined values, handle the ColumnView.BeforeLeaveRow event. The grid control has static fields specifying them. This also includes the GridControl.InvalidRowHandle value that is returned by some methods if a row handle cannot be obtained. In the code, check whether the current row is the New Item Row, and if so, display a confirmation message box.

Run the application. Focus the New Item Row and then try to change focus back to one of the data rows. If you click No, the focus will stay unchanged.

Expanded Converting Row Identifiers into One Another

Grid Views provide methods allowing you to convert row identifiers into one another. To see how this works, analyze the handler that displays row index information in this application.

There are three columns, one displays visible indexes, another row handles and the third - data source indexes. They are unbound and are populated using the ColumnView.CustomUnboundColumnData event. The code first obtains the row handle using the data source index passed as a parameter. Then, the visible index is determined using the row handle. After that all the values are displayed in their corresponding columns.

Expanded Key Points

Now go over the key points once again.

Data source indexes

  • Specify zero-based row indexes in the bound list.
  • Follow rows when you sort, group or filter data.
  • For group rows, they will point to the first data row in the group.
  • Used for accessing data.

Row Handles

  • Data row handles are zero-based indexes that correspond to row order from top to bottom.
  • Group row handles are negative values that start with -1. The order matches the order of group rows from top to bottom.
  • The grid specifies reserved row handles for the New Item Row, Auto Filter row and an Invalid Row Handle.
  • Row handles are re-assigned to rows after each data operation.
  • When the View is filtered, rows and row handles are created only for rows that match the filter.

Visible Indexes

  • Zero-based indexes that match the order of visible rows, from top to bottom.
  • Service rows get negative indexes if displayed above data and group rows.
  • Re-assigned after each data operation, including data sorting, grouping and filtering.
  • Visible indexes are only assigned to rows in expanded groups. Thus, the indexes are updated after each expand/collapse operation.

Expanded See Also

How would you rate this topic?​​​​​​​