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

Edit Data. Create Cell Editors. Validate User Input

  • 31 minutes to read

Read and Modify Cell Values in Code

Important

These methods should be called only when the Grid and its columns are fully initialized. If you need to call these methods while the form is still loading, call the ForceInitialize() method to force the Grid to finish its initialization.

Processed Cell

Read the Cell Value

Change the Cell Value

A focused cell

ColumnView.GetFocusedValue
ColumnView.FocusedValue

ColumnView.SetFocusedValue

A cell of a focused row

ColumnView.GetFocusedRowCellValue
ColumnView.GetFocusedRowCellDisplayText

ColumnView.SetFocusedRowCellValue

Any row cell

ColumnView.GetRowCellValue
ColumnView.GetRowCellDisplayText

ColumnView.SetRowCellValue

A cell value in an underlying data source

ColumnView.GetListSourceRowCellValue

The currently edited cell

ColumnView.EditingValue

ColumnView.EditingValue

The ColumnView.CellValueChanging and ColumnView.CellValueChanged events raise when a user changes a cell value.

The following code samples illustrate this API:

Example 1 - Get cell values

The code below retrieves the value of a cell that belongs to the “ID” column and the third data row (row handle equals 2).

string cellValue;
cellValue = gridView1.GetRowCellValue(2, "ID").ToString();
Example 2 - Get the focused cell text

This code returns the text displayed inside the currently focused cell.

string cellValue = gridView1.GetFocusedDisplayText();
Example 3 - Change the focused cell value

This example changes the value of the focused cell.

gridView1.SetRowCellValue(gridView1.FocusedRowHandle, gridView1.FocusedColumn, "New Value");
//or
gridView1.SetFocusedValue("New Value");
Example 4 - Post edit values immediately

A grid cell editor waits for a user to move focus to another cell or row before its new value is accepted. The code below forces editors to update their values immediately.

    BaseEdit edit = null;
    private void gridView1_ShownEditor(object sender, EventArgs e)
    {
        GridView view = sender as GridView;
        edit = view.ActiveEditor;
        edit.EditValueChanged += edit_EditValueChanged;       
    }

    void edit_EditValueChanged(object sender, EventArgs e)
    {
        gridView1.PostEditor();
    }

    private void gridView1_HiddenEditor(object sender, EventArgs e)
    {
        edit.EditValueChanged -= edit_EditValueChanged;
        edit = null;
    }
Example 5 - Auto-adjust cell values

In the Change column cell values based on another column’s values demo, checkboxes under the “Mark” column are automatically checked if you enter a “Length” of more than 10, and cleared otherwise.

gridView.CellValueChanged += (sender, e) => {
    GridView view = sender as GridView;
    if (e.Column.FieldName == "Length") {
        double doubleVal = (double)e.Value;
        view.SetRowCellValue(e.RowHandle, "Mark", doubleVal > 10);
    }
};

Note

  • In Data Grids that display master-detail data sets, detail data is stored in Clone Views, not Pattern Views. To access this data, call the GridView.GetDetailView method to retrieve a Clone View instance, and use its GetCellValue or GetRow methods. See this help topic for more information: Working with Master-Detail Relationships in Code.
  • You cannot obtain or modify cell values until there is a row object that corresponds to a record. If a user utilizes the New Item Row to add new rows, the Data Grid initializes new row objects for these rows only after the user modifies a cell.

Cell Editors

Editor Container Architecture: Repository Items and Real Editors

All DevExpress Editors have related repository items. For instance, a RepositoryItemSpinEdit object is a repository item for the SpinEdit editor. Repository items are cores that store a set of properties required to generate an editor. To access an editor’s repository item, use the BaseEdit.Properties property.

All inactive Grid cells contain repository items. When a user clicks a cell to edit its value, the cell’s repository item creates an editor. After a user edits the cell value and deselects this cell (or after you call the CloseEditor/HideEditor methods in code), its editor is destroyed. As a result, an initialized cell editor exists only when the Grid is in edit mode. This technique improves Data Grid performance.

repositories

Default Cell Editors

The Data Grid includes support for in-place data editors. To edit a cell value at runtime, a user should focus it and press Enter, or click this cell. The actual behavior depends on the EditorShowMode value. To discard edits, press Esc.

Columns utilize DevExpress Editors to display and edit data source records. Columns automatically choose editors depending on the column data type. For instance, if a column displays dates, it will utilize the DateEdit in-place editor.

Data Grid - Date Edit In-Place Editor

Demos: Inplace Cell Editors | Show buttons in grid cells

Replace Default Cell Editors at Design Time

To modify an in-place editor for a Data Grid column, invoke the column’s smart tag menu and use the GridColumn.ColumnEdit property’s drop-down menu to create a new or choose an existing editor.

Data Grid - Column Edit Smart Tag

The Data Grid Designer’s “In-place Editor Repository” page provides centralized access to all in-place editors. In this section, you can add, modify, and remove editors.

Data Grid - Repository Items Designer

Replace Default Cell Editors in Code

To use custom editors for column cells, assign related repository items to the GridColumn.ColumnEdit property. The Assign in-place editors (repository items) demo illustrates how to replace standard checkboxes for the “Mark” column with ToggleSwitch editors.

    // Assign a repository item to a column            
    RepositoryItemToggleSwitch edit = new RepositoryItemToggleSwitch();
    gridControl.RepositoryItems.Add(edit);
    gridView.Columns["Mark"].ColumnEdit = edit;

If you need to specify an in-place editor for a specific cell rather than an entire column, handle the GridView.CustomRowCellEdit event. Note that any repository item you create in code must be manually added to the grid control’s EditorContainer.RepositoryItems collection.

Example 1 - Progress Bar as a Cell Editor for a Numeric Column

The code below illustrates how to utilize a ProgressBarControl as an in-place editor for the integer “Relevance” grid column. Users can tap or hold numpad “+” and “-“ keys to modify these integer values.

using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraEditors.Repository;

// Create a repository item
RepositoryItemProgressBar ieProgress = new RepositoryItemProgressBar();
gridControl1.RepositoryItems.Add(ieProgress);
ieProgress.KeyPress += IeProgress_KeyPress;

// Assign the repository item
colRelevance.ColumnEdit = ieProgress;
// Or
private void GridView1_CustomRowCellEdit(object sender, CustomRowCellEditEventArgs e) {
    if (e.Column == colRelevance) e.RepositoryItem = ieProgress;
}

// Handle + and - key presses
private void IeProgress_KeyPress(object sender, KeyPressEventArgs e) {
    int i = 0;
    if (gridView1.ActiveEditor == null) return;

    if (e.KeyChar == '+') {
        i = (int)gridView1.ActiveEditor.EditValue;
        if (i < 100)
            gridView1.ActiveEditor.EditValue = i + 1;
    }
    if (e.KeyChar == '-') {
        i = (int)gridView1.ActiveEditor.EditValue;
        if (i > 0)
            gridView1.ActiveEditor.EditValue = i - 1;
    }
}
Example 2 - Place buttons inside Grid cells

The Cell commands to edit and delete rows demo has a “Commands” column with a ButtonEdit cell editor. The editor has two buttons: Edit invokes the Edit Form, Delete removes the current row.

buttonEdit

    // Create the Commands column editor
    RepositoryItemButtonEdit commandsEdit = new RepositoryItemButtonEdit { AutoHeight = false, Name = "CommandsEdit", TextEditStyle = TextEditStyles.HideTextEditor };
    commandsEdit.Buttons.Clear();
    commandsEdit.Buttons.AddRange(new EditorButton[] {
    new EditorButton(ButtonPredefines.Glyph, "Edit", -1, true, true, false, ImageLocation.MiddleLeft, DemoHelper.GetEditImage()),
    new EditorButton(ButtonPredefines.Glyph, "Delete", -1, true, true, false, ImageLocation.MiddleLeft, DemoHelper.GetDeleteImage())});
    grid.RepositoryItems.Add(commandsEdit);

    // Create an unbound Commands column
    GridColumn _commandsColumn = gridView.Columns.AddField("Commands");
    _commandsColumn.UnboundDataType = typeof(object);
    _commandsColumn.Visible = true;
    _commandsColumn.Width = 100;

    // Hide commandsColumn from EditForm
    _commandsColumn.OptionsEditForm.Visible = DevExpress.Utils.DefaultBoolean.False;

    // Display commands only for the focused row
    gridView.CustomRowCellEdit += (s, e) => {
        if (e.RowHandle == gridView.FocusedRowHandle && e.Column == _commandsColumn)
            e.RepositoryItem = commandsEdit;
    };
    gridView.CustomRowCellEditForEditing += (s, e) => {
        if (e.RowHandle == gridView.FocusedRowHandle && e.Column == _commandsColumn)
            e.RepositoryItem = commandsEdit;
    };

    // Allow only commandsColumn to be edited
    gridView.ShowingEditor += (s, e) => {
        e.Cancel = gridView.FocusedColumn != _commandsColumn;
    };

    gridView.OptionsEditForm.ShowOnDoubleClick = DevExpress.Utils.DefaultBoolean.False;
    gridView.OptionsEditForm.ShowOnEnterKey = DevExpress.Utils.DefaultBoolean.False;
    gridView.OptionsEditForm.ShowOnF2Key = DevExpress.Utils.DefaultBoolean.False;
    gridView.OptionsBehavior.EditingMode = GridEditingMode.EditFormInplace;

    // Perform a specific action when an EditorButton is clicked
    commandsEdit.ButtonClick += (s, e) => {
        switch (e.Button.Caption) {
            case "Edit":
                // Start editing a row using EditForm
                gridView.CloseEditor();
                gridView.ShowEditForm();
                break;
            case "Delete":
                // Delete focused row
                gridView1.DeleteRow(gridView1.FocusedRowHandle);
                break;
        }
    };
Example 3 - Use different editors for cells of the same column

In the Assign in-place editors dynamically demo, the “Length” column receives either a SpinEdit or a CalcEdit editor depending on whether the checkbox under the “Mark” column is checked.

RepositoryItemSpinEdit spinEdit = new RepositoryItemSpinEdit();
RepositoryItemCalcEdit calcEdit = new RepositoryItemCalcEdit();
grid.RepositoryItems.Add(spinEdit);
grid.RepositoryItems.Add(calcEdit);
gridView.Columns["Length"].ShowButtonMode = ShowButtonModeEnum.ShowAlways;

// Handle this event to assign editors to individual cells
gridView.CustomRowCellEdit += (sender, e) => {
    GridView view = sender as GridView;
    if (e.Column.FieldName == "Length") {
        bool boolVal = (bool)view.GetRowCellValue(e.RowHandle, "Mark");
        if (boolVal)
            e.RepositoryItem = spinEdit;
        else
            e.RepositoryItem = calcEdit;
    }
};

You can also handle the GridView.CustomRowCellEdit event to replace a default cell editor with an editor of the same type, but with modified settings. This technique is illustrated in the following example: Disable Buttons in Certain Rows.

Example 4 - Toggle editor button visibility or availability

The code sample below creates two identical [](xref:DevExpress.XtraEditors.Repository.RepositoryItemButtonEdit editors with buttons that copy or remove a cell value. Buttons of one editor are enabled while buttons of the other editor are disabled. The code inside the CustomRowCellEdit event handler assigns the appropriate editor to the “Notes” cells based on whether the adjacent “Mark” cell is checked.

disabled_button_demo

gridView.OptionsView.ShowButtonMode = ShowButtonModeEnum.ShowAlways;

RepositoryItemButtonEdit riButtonEditEnabled = new RepositoryItemButtonEdit();
riButtonEditEnabled.Buttons.Clear();
riButtonEditEnabled.Buttons.Add(new EditorButton(ButtonPredefines.Plus, "Copy cell value"));
riButtonEditEnabled.Buttons.Add(new EditorButton(ButtonPredefines.Delete, "Clear this cell"));
grid.RepositoryItems.Add(riButtonEditEnabled);

RepositoryItemButtonEdit riButtonEditDisabled = new RepositoryItemButtonEdit();
// Create a similar RepositoryItem 
riButtonEditDisabled.Assign(riButtonEditEnabled);
// Disable all buttons
riButtonEditDisabled.Buttons.ToList<EditorButton>().ForEach(button => button.Enabled = false);
grid.RepositoryItems.Add(riButtonEditDisabled);

gridView.CustomRowCellEdit += (s, e) => {
    if (e.Column.FieldName == "Notes") {
        GridView view = s as GridView;
        bool actionsAvailable = Convert.ToBoolean(view.GetRowCellValue(e.RowHandle,"Mark"));
        e.RepositoryItem = actionsAvailable ? riButtonEditEnabled : riButtonEditDisabled;
    }
};

Demos: Assign in-place editors (repository items) | Assign in-place editors dynamically

Use Any Control as a Cell Editor

The RepositoryItemAnyControl allows you to embed any static control into a grid cell. The figure below illustrates an embedded Chart Control.

Data Grid - In-Place Chart Control

In order to embed a control, it must implement the DevExpress.XtraEditors.CustomEditor.IAnyControlEdit interface. The Gauge Control implements this interface out of the box. To embed other controls, you need to implement this interface manually.

Embedded Gauge Control: Demo | Example

Embedded Chart Control: Demo | Example

Use Different Controls to Display and Edit Cell Values

Any Data Grid cell uses the same editor to display and edit data. If you require a cell to utilize one editor when a user browses data records, and another editor when a user modifies this cell’s value, handle the GridView.CustomRowCellEditForEditing event.

In the example below, a column with numeric values uses a ProgressBarControl to display cell values. ProgressBar editors do not have UI elements a user can interact with to modify cell values. For a better user experience, when a cell enters Edit mode (users can double-click cells to start editing cell values), the ProgressBar editor is replaced with the SpinEdit editor. Once the editor is back in Display mode (a user presses Enter or focuses another cell), the ProgressBar is visible again.

using DevExpress.XtraEditors.Repository;

// Create separate editors for Display and Edit modes.
RepositoryItem editorForDisplay, editorForEditing;

private void Form1_Load(object sender, EventArgs e) {
    // Initialize the editors and assign the default editor to a column.
    editorForDisplay = new RepositoryItemProgressBar();
    editorForEditing = new RepositoryItemSpinEdit();
    gridView1.GridControl.RepositoryItems.AddRange( 
      new RepositoryItem[] { editorForDisplay, editorForEditing });
    gridView1.Columns["Quantity"].ColumnEdit = editorForDisplay;
}

// Assign the editor for in-place editing.
private void gridView1_CustomRowCellEditForEditing(object sender, 
  CustomRowCellEditEventArgs e) {
    if (e.Column.FieldName == "Quantity")
        e.RepositoryItem = editorForEditing;
}

Demo: Override the default in-place editor for certain cells

Manage Cell Editors in Code

API

Description

BaseView.ShowEditor

Invokes the focused cell’s editor

BaseView.HideEditor

Closes the currently active editor and discards any changes

BaseView.CloseEditor

Saves any changes made and closes the currently active editor

BaseView.PostEditor

Saves any changes made without closing the currently active editor

BaseView.ActiveEditor

Retrieves the currently active editor

ColumnView.ShownEditor

Fires whenever an in-place editor activates. The code below automatically sets the current date and opens the DateEdit popup when users activate the “Order Date” column editor.

using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraEditors;
//. . .
gridView1.ShownEditor += GridView1_ShownEditor;
//. . .
private void GridView1_ShownEditor(object sender, EventArgs e) {
    GridView View = sender as GridView;
    if (View.FocusedColumn == colOrderDate) {
        // Add the current date
        View.EditingValue = DateTime.Today;
        // Obtain the active editor
        DateEdit editor = View.ActiveEditor as DateEdit;
        // Invoke the editor's popup window
        editor.ShowPopup();
    }
}

ColumnView.HiddenEditor

Fires whenever an in-place editor closes. In the code sample below, focus automatically moves to the cell below after the editor for the current cell closes. This feature allows users to edit each cell within a single column without the need to move focus. This code is not executed when users work with a New Item Row.

using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraEditors;
//. . .
gridView1.HiddenEditor += GridView1_HiddenEditor;
//. . .
private void GridView1_HiddenEditor(object sender, EventArgs e) {
    GridView View = sender as GridView;
    if (View.FocusedRowHandle == GridControl.NewItemRowHandle) return;
    if (View.FocusedRowHandle == View.RowCount - 1)
        View.FocusedRowHandle = 0;
    else
        View.FocusedRowHandle++;
    View.ShowEditor();
}

OptionsBehavior.EditorShowMode

Specifies how a cell editor is activated by the mouse.

The following example shows how to always display editor buttons and let users click editor buttons on the first click:

Editor Show Mode - WinForms Data Grid, DevExpress

using DevExpress.Utils;
using DevExpress.XtraGrid.Views.Base;

private void Form1_Load(object sender, EventArgs e) {
    gridView1.OptionsBehavior.EditorShowMode = EditorShowMode.MouseDown;
    gridView1.OptionsView.ShowButtonMode = ShowButtonModeEnum.ShowAlways;
}

Edit Data in a Separate Form

Edit Form

Users can use an Edit Form instead of in-place editors to modify grid records. To invoke this form, double-click a grid row at runtime or press the Enter or F2 key.

Data Grid - Inline Edit Form

For regular Views you can select one of three available Edit Form display modes:

  • A floating modal form (default mode).
  • An in-place form displayed below the grid row that is being edited.
  • An in-place form displayed instead of the edited row.

Detail Views do not support in-line edit forms.

Related API

API

Description

GridOptionsBehavior.EditingMode

Allows you to turn on the Edit Form and select its display mode.

GridView.ShowEditForm
GridView.HideEditForm

Call these methods to manually display and hide an Edit Form.

GridOptionsEditForm.ActionOnModifiedRowChange

Specifies whether to show confirmation dialogs when users modify records.

GridOptionsEditForm.ShowUpdateCancelPanel

Gets or sets whether the “Update” and “Cancel” buttons should be displayed. When these buttons are hidden, users can still utilize hotkeys to save (Ctrl+Enter) or discard (Escape) changes.

GridOptionsEditForm.BindingMode

Specifies whether to pass changes to a Data Grid immediately after a user moves focus to another Edit Form field, or only after all changes have been accepted.

GridOptionsEditForm.FormCaptionFormat

Allows you to modify a caption of a floating Edit Form.

GridView.EditFormShowing

Fires when the Edit Form is about to be shown, and allows you to hide the Edit Form when you do not want users to edit specific cell values. The following example from the Prevent the Edit Form from Showing demo disables edit operations for even rows:

gridView.OptionsBehavior.EditingMode = GridEditingMode.EditForm;

gridView.EditFormShowing += (s, e) => {
    if (e.RowHandle % 2 == 0)
        e.Allow = false;
};

Important

The Edit Form uses the Tag property of repository items internally. Do not set the Tag property to avoid runtime issues.

Demos: Inline Edit Form | Prevent the Edit Form from showing | Access an editor within the Edit Form

Modify Values of EditForm Editors and Implement Custom Edit Logic

EditForm is a ContainerControl with editors bound to properties of an underlying data record. To modify values of these editors or implement a custom edit logic, do one of the following:

  • Create a custom EditForm and implement the required editor behavior.
  • Handle the GridView.EditFormPrepared event to access and customize default EditForm editors.

The following code from the Access an Editor Within the Edit Form demo illustrates how to use the second technique to find the DateEdit editor and focus it.

gridView.OptionsBehavior.EditingMode = GridEditingMode.EditForm;
DateEdit dateEdit = null;

// This event occurs when the EditForm is about to be displayed and allows accessing its editors
gridView.EditFormPrepared += (s, e) => {
    // The e.BindableControls collection contains a list of editors located on the EditForm
    foreach (Control item in e.BindableControls) {
        dateEdit = item as DateEdit;
        if (dateEdit != null) {
            // Focus the DateEdit editor
            dateEdit.Select();
            return;
        }
    }
};

Always remember to remove references to EditForm controls and unsubscribe from event handlers. To do this, handle the EditFormHidden event.

This guideline is applicable to other data-aware controls that support Edit Forms: Gantt Control, Tree List, etc.

Modify Edit Form Layout

The default Edit Form layout is built according to the following rules:

  • An Edit Form displays an editor for every visible editable column.
  • If a column uses different editors to edit and display cell values, an Edit Form uses editors utilized by cells in Edit mode.
  • An Edit Form’s client area has a table layout with three columns. Each editor (except for MemoEdit and PictureEdit editors) occupies a single cell.
  • MemoEdit editors span across all layout columns horizontally and three layout rows vertically.
  • PictureEdit editors span across two layout columns horizontally and three layout rows vertically.

To modify this default layout, invoke the Data Grid Designer and switch to its “Edit Form Designer” page. In this page, you can modify layout settings of every column editor.

Data Grid - Edit Form Designer

Related API

API

Description

GridColumn.OptionsEditForm

Provides access to layout settings that affect how an editor for this specific column looks within an Edit Form (see below).

OptionsColumnEditForm.UseEditorColRowSpan

Disable this setting to set custom column and row spans for an editor.

OptionsColumnEditForm.ColumnSpan
OptionsColumnEditForm.RowSpan

Specify the number of Edit Form columns and/or rows across which an editor stretches.

OptionsColumnEditForm.Caption
OptionsColumnEditForm.CaptionLocation

Allow you to modify the editor caption and its relative position.

OptionsColumnEditForm.Visible
OptionsColumnEditForm.VisibleIndex

Use these properties to hide and rearange column editors.

OptionsColumnEditForm.StartNewRow

Set this option to true to move the editor to a new row.

Create Custom Edit Forms

You can create your own User Control and utilize it instead of the default Edit Form.

  1. Create a User Control and inherit it from the EditFormUserControl class.
  2. If you have partial classes for this User Control, they must inherit the EditFormUserControl class as well.
  3. Design your custom User Control UI.
  4. Use the BoundFieldName and BoundPropertyName extender properties of the parent class to bind editors to data source fields.
  5. Assign an instance of the custom edit form to the Data Grid GridOptionsEditForm.CustomEditFormLayout property.
  6. To use this custom form in detail Views, assign separate form instances to each detail View.
using DevExpress.XtraGrid.Views.Grid;
// Custom Edit Form
public class AdvancedEditForm : EditFormUserControl {
    public AdvancedEditForm() {
        InitializeComponent();
        // Bind the EditValue of the textEdit3 editor to the "Price" data field
        this.SetBoundFieldName(textEdit3, "Price");
        this.SetBoundPropertyName(textEdit3, "EditValue");
    }
}

// Use the custom Edit Form in non-master-detail Data Grids
gridView1.OptionsEditForm.CustomEditFormLayout = new AdvancedEditForm();

// Use custom Edit Forms for detail Views
void gridControl1_ViewRegistered(object sender, DevExpress.XtraGrid.ViewOperationEventArgs e) {
    GridView detailCloneView = e.View as GridView;
    if(detailCloneView.LevelName == "Order_Details")
        detailCloneView.OptionsEditForm.CustomEditFormLayout = new AdvancedEditForm(); 
}

Demos: Custom Edit Form | Inline Edit Form

Tip

You can also use a custom form to edit data. See the following KB article for information on how to implement a custom form: Implementing CRUD operations in read-only data sources using XtraGrid.

Manage End-User Input

Use Masks to Limit Data Input

Since DevExpress editors support Masks, you can prevent a user from entering invalid characters. The sample below illustrates how to allow users to enter 10-digit phone numbers with the automatically added “+1” country code.

repositoryItemTextEdit2.Mask.EditMask = "+1 (000) 000-0000";
repositoryItemTextEdit2.Mask.MaskType = DevExpress.XtraEditors.Mask.MaskType.Numeric;
repositoryItemTextEdit1.Mask.UseMaskAsDisplayFormat = true; // Optional
grid.RepositoryItems.Add(repositoryItemTextEdit1);
gridView.Columns["Phone"].ColumnEdit = repositoryItemTextEdit2;

Make Certain Grid Cells Non-Editable

You can prevent users from editing all cell values in a Grid (or column) or specific cell values based on a custom condition.

Global Grid Settings

Conditionally Disable In-Place Editing

  • Use the Disabled Cell Behavior to disable cells in rows that meet a certain condition. Disabled cells are grayed-out and cannot be edited.
  • Handle the ColumnView.ShowingEditor event and set its Cancel parameter to true. For instance, the code snippet below prohibits users from editing records whose “Country” field equals “Germany”.

    using DevExpress.XtraGrid.Views.Grid;
    // ... 
    private void gridView1_ShowingEditor(object sender, System.ComponentModel.CancelEventArgs e) {
       GridView View = sender as GridView;
       string cellValue = View.GetRowCellValue(View.FocusedRowHandle, colCountry).ToString();
       if (cellValue == "Germany")
           e.Cancel = true;
    }
    

You can also check the Read-only mode for certain cells demo where you cannot edit the “ID” column cells for every odd row.

gridView.ShownEditor += (s, e) => {
    GridView view = s as GridView;
    view.ActiveEditor.Properties.ReadOnly =
        gridView.FocusedColumn.FieldName == "ID" && gridView.FocusedRowHandle % 2 == 0;
};

These settings affect only users and do not prevent you from modifying cell values in code.

Demos: Run Demo: Non-editable mode Run Demo: Prohibit users from editing certain GridView cells

Conditionally Disable Edit Form Fields

If users utilize an Edit Form to edit cell values, use one of the following techniques to disable the Form’s fields:

Validate Cell Values

Data Grid validates its cell value when a user finishes editing this value and presses Enter or moves focus to another cell within the same row. To forcibly trigger validation, call the BaseView.PostEditor method. The diagram below illustrates this validation process.

Data Grid - Validation - Cell Validation

  • BaseView.ValidatingEditor - handle this event to check whether a new cell value is correct and set the Boolean e.Valid parameter accordingly. Users are unable to move focus away from a cell with an incorrect value until the error is fixed or the “Esc” key is pressed to undo changes.

  • BaseView.InvalidValueException - raises if the e.Valid parameter of the previous event has been set to false and allows you to specify how the Data Grid responds to an invalid value. See the ExceptionMode enumerator values to see the available options.

  • If the ExceptionMode parameter is set to NoAction, a cell does not accept an invalid value and the Grid does not display any notifications. Use this technique if you want to implement custom notifications. For instance, you can call the ColumnView.SetColumnError method to set default error icons for multiple columns at once.

Example 1 - How to compare cell values

The code sample below checks the order shipping date, which cannot be earlier than the date this order was placed.

Data Grid - Validation Dates

private void GridView1_ValidatingEditor(object sender, BaseContainerValidateEditorEventArgs e) {
    GridView view = sender as GridView;
    if (view.FocusedColumn == colRequiredDate) {
        DateTime? requiredDate = e.Value as DateTime?;
        DateTime? orderDate = view.GetRowCellValue(view.FocusedRowHandle, colOrderDate) as DateTime?;
        if (requiredDate < orderDate) {
            e.Valid = false;
            e.ErrorText = "Required Date is earlier than the order date";
        }
    }
}
Example 2 - How to avoid duplicate values

The following code from the Prevent entering duplicate values demo illustrates how to check the “ID” column values and prevent users from entering non-unique IDs.

gridView.ValidatingEditor += (s, e) => {
    string fieldName = string.Empty;
    GridView view = s as GridView;
    EditFormValidateEditorEventArgs ea = e as EditFormValidateEditorEventArgs;
    if(ea == null)
        fieldName = view.FocusedColumn.FieldName;
    else
        fieldName = ea.Column.FieldName;
    int rowCellValue;
    int validatingCellValue = Convert.ToInt32(e.Value);
    if(fieldName == "ID")
        // Iterate through all data rows within GridView
        for(int rowHandle = 0; rowHandle < view.DataRowCount; rowHandle++) {
            // Obtain the ID cell value of the processed row
            rowCellValue = Convert.ToInt32(view.GetRowCellValue(rowHandle, fieldName)); 
            if(rowCellValue == validatingCellValue) {
                e.Valid = false;
                e.ErrorText = "ID should be unique (ValidatingEditor)";
                return;
            }
        }
};

gridView.InvalidValueException += (s, e) => {
    e.ExceptionMode = ExceptionMode.DisplayError;
};

The Data Validation demo utilizes a different cell validation approach and employs the GridView.RowCellStyle event to highlight cells with invalid values.

Demos: Data Validation | Validate the active editor’s value | Prevent entering duplicate values

Validate Rows

When the Data Grid validates rows, it does not check cell values until a user moves focus to another row. This can be useful to identify cases where a cell value is technically correct, but conflicts with other cells in the same row. For example, a “Shipping Date” cell stores a valid date, but this date is earlier than its corresponding “Order Date” cell value. To manually trigger row validation, call the ColumnView.UpdateCurrentRow method.

Data Grid - Validation - Row Diagram

  • ColumnView.ValidateRow / ColumnView.InvalidRowException events - Similar to per-cell validation, these events allow you to validate new cell values and respond to invalid values. If new cell values do not pass validation, users are kept on the current row to either correct all errors, or press Esc and undo the changes. Note that to revert row cell values back to correct values, data source objects must implement the IEditableObject interface.

  • ColumnView.SetColumnError method - If a row is invalid, the Data Grid displays a message that requires a user to either correct or discard the invalid values. To suppress this default notification, call the ColumnView.SetColumnError method to mark specific cells (or the entire row) as invalid manually.

In the Data Validation demo, the ValidateRow event is handled to calculate values of the “Sub Total” column cells based on the “Unit Price”, “Quantity” and “Discount” column cells. Negative subtotal values are not accepted.

Data Grid - Validate Row Demo

private void gridView1_ValidateRow(object sender, DevExpress.XtraGrid.Views.Base.ValidateRowEventArgs e) {
    GridView view = sender as GridView;
    float val = Convert.ToSingle(view.GetRowCellValue(e.RowHandle, gridColumn3)) * 
        Convert.ToInt16(view.GetRowCellValue(e.RowHandle, gridColumn4)) *
        (1 - Convert.ToSingle(view.GetRowCellValue(e.RowHandle, gridColumn5))); //Total Sum
    if(val < 0) {
        e.ErrorText = string.Format("{0}\r\n", Properties.Resources.SubTotalGreaterEqual);
        e.Valid = false;
    }
}

Demos: Data Validation | Validate row data on losing focus

Indicate Invalid Values with IDXDataErrorInfo

Use the DXErrorProvider component and implement the IDXDataErrorInfo interface in a business object to automatically indicate invalid values and display text-based feedback (tooltips).

Indicate Invalid Values with IDXDataErrorInfo - WinForms Data Grid Validation

using DevExpress.XtraGrid.Views.Base;
using DevExpress.XtraEditors.DXErrorProvider;

namespace DXApplication {
    public partial class Form1 : DevExpress.XtraEditors.XtraForm {
        DXErrorProvider errorProvider;
        public Form1() {
            InitializeComponent();
            // Initializes a data source and binds it to the grid control.
            List<MyRecord> records = MyRecord.InitData();
            gridControl1.DataSource = records;
            // Initializes the DXErrorProvider component that handles errors.
            errorProvider = new DXErrorProvider(this);
            // Binds the error provider to the data source to track errors.
            errorProvider.DataSource = records;
        }
    }

    public class MyRecord : IDXDataErrorInfo {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public void GetPropertyError(string propertyName, ErrorInfo info) {
            if(propertyName == "FirstName" && FirstName == "" ||
                propertyName == "LastName" && LastName == "")
                info.ErrorText = string.Format("The {0} field cannot be empty", propertyName);
        }
        public void GetError(ErrorInfo info) { }
        static public List<MyRecord> InitData() {
            return new List<MyRecord>() {
                new MyRecord(){ FirstName = "Mike", LastName = "Brown" },
                new MyRecord(){ FirstName = "Sandra", LastName = "Smith"},
                new MyRecord(){ FirstName = "Andy", LastName = "Muller" }
            };
        }
    }
}

Save User Edits

Data Grid and other DevExpress data-aware controls (Gantt Control, Vertical Grid, TreeList, etc.) do not interact with real data storages. Instead, they use data sources connected to these storages. Data-aware controls save user edits to data sources, but you need to manually post these changes to underlying storages. See this help topic for more information: Post Data to an Underlying Data Source.

To post modified row values to an underlying source, handle the ColumnView.RowUpdated event. This event fires when a user navigates away from the edited row.

void gridView1_RowUpdated(object sender, RowObjectEventArgs e) {
    //use data source API to save changes
}

If you want to save changes every time a user edits a cell, handle the ColumnView.CellValueChanged event instead.

Note that before you save data to a storage, you need to ensure there is no active editor (the BaseView.IsEditing property returns false). Call the BaseView.CloseEditor method to close the active editor, and then call the BaseView.UpdateCurrentRow method.

void gridView1_CellValueChanged(object sender, CellValueChangedEventArgs e)  {
    ColumnView view = sender as ColumnView;  
    view.CloseEditor();  
    if(view.UpdateCurrentRow()) {  
        //use data source API to save changes
    }
}
See Also