Skip to main content

Unbound Rows

  • 7 minutes to read

The VGridControl control supports bound and unbound rows. This topic introduces unbound rows - rows that are not bound to any field in a grid’s data source.


Bound and Unbound Rows

Bound rows obtain their data from a grid’s data source, which is specified by the VGridControl.DataSource and VGridControl.DataMember properties. Their RowProperties.FieldName properties refer to valid fields in a data source.

An unbound row is not bound to any field in an underlying data source. You can provide data for unbound rows using one of two methods:

  • by specifying a formula (string expression) via the RowProperties.UnboundExpression property used to automatically evaluate values for this row. Expressions allow you to calculate values based on values of other rows. You can use constants, various functions and operators in expressions. See Expressions to learn about the syntax.
  • by handling the VGridControl.CustomUnboundData event. In this event, you can implement custom logic of any complexity.

    With this event, you can enable an end-user to edit values in unbound rows. When an end-user modifies a cell, the CustomUnboundData event fires allowing you to save the changes.


    The CustomUnboundData event fires only for visible unbound rows.

An unbound row must meet the following two requirements:

  • its field name (RowProperties.FieldName) must be set to a unique value and not refer to any field in a grid’s data source;
  • the row’s RowProperties.UnboundDataType property must be set to the type of data the row is supposed to display (Boolean, DateTime, Decimal, Integer, String, Object, and so forth).

The UnboundDataType property determines the default cell editor, value alignment and validity rules.

Note that you can also assign a specific editor to a row via the RowProperties.RowEdit property and to a specific cell via the VGridControlBase.CustomRecordCellEdit and VGridControlBase.CustomRecordCellEditForEditing events.

If the UnboundDataType property is not set it is assumed that the row is bound to a data source field (RowProperties.FieldName).

Unbound Rows’ Data

You can provide data for unbound rows either by creating an expression via the RowProperties.UnboundExpression property or by handling the VGridControl.CustomUnboundData event. To learn about the syntax of expressions, see Expressions.

At runtime, an end-user can edit an unbound row’s expression via an Expression Editor. It can be opened via a context menu (if the RowProperties.ShowUnboundExpressionMenu option is enabled) or in code via the VGridControl.ShowUnboundExpressionEditor method.

By default, data editing is enabled in unbound row cells. However, you may wish to prevent an end-user from editing unbound rows. To make a row read-only, use the RowProperties.ReadOnly property.

If you want to save the changes made by end-users in unbound rows, you should populate an unbound row via the VGridControl.CustomUnboundData event. This event’s IsGetData and IsSetData parameters determine the event’s current mode of operation. If the IsGetData parameter is set to true (and consequently the IsSetData parameter is set to false), the event handler should supply data for an unbound row. A value should be assigned to the Value parameter according to the record currently being processed. The current record can be identified using the ListSourceRowIndex parameter, which specifies the record’s index in a grid’s data source.

If the IsSetData parameter is set to true (and consequently the IsGetData parameter is set to false), the event has been fired as a result of data modifications within a grid. In this case, the Value parameter contains modified data and should be stored for further use.


If you need to get or set specific cell values while handling the CustomUnboundData event, use methods provided by the bound data source. The event’s ListSourceRowIndex parameter allows you to identify the current data record.

Do not use methods provided by the grid control (for example, VGridControlBase.GetCellValue and VGridControlBase.SetCellValue) to get/set cell values in a CustomUnboundData event.

Working with Unbound Rows

There is no difference between working with bound and unbound rows.

However, please keep in mind those situations in which unbound rows retrieve their data from a custom data source, and a record is added to or deleted from a grid’s main data source. When a record is added, you usually need to add a new entry to the custom data source that corresponds to the new record in the grid. Similarly, when a record is deleted you usually need to delete the corresponding entry in the custom data source. To receive notifications about a record that has been added or removed, use the methods provided by the data source.

When printing or exporting a grid, the contents of unbound rows will be printed/exported as well.

Reload Data in Unbound Rows

To reload data in unbound rows and redraw the control on-screen, call the VGridControlBase.LayoutChanged method. The control also reloads data in unbound rows when you sort or filter data.

Custom Display Text

With their editing feature disabled, unbound rows can be used to display custom read-only information. It is also possible to provide custom display text for cells using the VGridControlBase.CustomDrawRowValueCell event. The custom display text supplied via this event is not printed or exported.

Example 1

This example demonstrates how to create an editable unbound row. It uses a simple cache implementation within the CustomUnboundData event handler to fetch custom data faster.

using DevExpress.XtraVerticalGrid.Rows;

private void CreateUnboundRow() {
    EditorRow row = vGridControl1.Rows.AddEditorRow("UnboundRow");
    row.Properties.UnboundDataType = typeof(string);

Dictionary<int, string> storage = new Dictionary<int, string>();
private void vGridControl1_CustomUnboundData(object sender, DevExpress.XtraVerticalGrid.Events.CustomDataEventArgs e) {
    if(e.RowProperties.FieldName == "UnboundRow") {
                e.Value = storage[e.ListSourceRowIndex];
                e.Value = storage[e.ListSourceRowIndex] = string.Format("Unbound value {0}", e.ListSourceRowIndex);
            storage[e.ListSourceRowIndex] = e.Value.ToString();

Example 2

In the following example, it is assumed that the Vertical Grid is bound to a table that contains the “Quantity”, “UnitPrice” and “Discount” fields. The code below adds an unbound row that calculates the total order amount according to the following expression: Quantity*UnitPrice*(1-Discount).


using DevExpress.XtraVerticalGrid;
using DevExpress.XtraVerticalGrid.Rows;
using DevExpress.Data;
using DevExpress.Utils;
using DevExpress.XtraVerticalGrid.Events;

// Unbound row.
EditorRow rowTotal = null;

private void Form1_Load(object sender, EventArgs e) {
    // ...
    vGridControl1.CustomUnboundData += new CustomDataEventHandler(vGridControl1_CustomUnboundData);
    // Create and initialize the unbound Total row.
    rowTotal = new EditorRow();
    rowTotal.Properties.Caption = "Total";
    rowTotal.Properties.FieldName = "Total";
    // Specify format settings.
    rowTotal.Properties.Format.FormatType = FormatType.Numeric;
    rowTotal.Properties.Format.FormatString = "c";            
    // Disable edit operations.
    rowTotal.Properties.ReadOnly = true;            
    rowTotal.Properties.UnboundDataType = typeof(decimal);
    // Customize the appearance settings.
    rowTotal.Appearance.BackColor = Color.FromArgb(179, 226, 221);
    rowTotal.Appearance.Font = new System.Drawing.Font(rowTotal.Appearance.Font, 

// Provide data for the Total row.
private void vGridControl1_CustomUnboundData(object sender, CustomDataEventArgs e) {
    VGridControl vGrid = sender as VGridControl;
    if (e.Row == rowTotal && e.IsGetData) {
        DataRowView row = (DataRowView)vGrid.GetRecordObject(e.ListSourceRowIndex);
        decimal unitPrice = Convert.ToDecimal(row["UnitPrice"]);
        decimal quantity = Convert.ToDecimal(row["Quantity"]);
        decimal discount = Convert.ToDecimal(row["Discount"]); ;
        e.Value = unitPrice * quantity * (1 - discount);