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

Edit Data in Blazor Grid

  • 11 minutes to read

Users can employ an inline edit row or invoke a standard or pop-up edit form to edit data in the Grid. This topic describes how to enable data editing and customize edit-related options.

Run Demo: Edit Forms Watch Video: Grid - Edit Data

Enable Editing

Follow the steps below to allow users to add, edit, and delete data rows.

Tip

To review the complete sample project, refer to the following GitHub example:
Bind the Grid to data with Entity Framework Core

1. Show UI Elements

Declare a DxGridCommandColumn object in the Columns template. This column displays predefined New, Edit, and Delete command buttons.

<DxGrid Data="Data" ...>
    <Columns>
        <DxGridCommandColumn />
        @*...*@
    </Columns>
</DxGrid>

Blazor Grid Command Column

To hide unnecessary buttons, disable the following options:

Specify the FixedPosition property to anchor the column to the left or right border of the Grid.

Once a user clicks the New or Edit button, the edit row or form appears. You can handle the EditStart event to create a custom response to a start edit action. When the user clicks the Delete button, the Grid displays the delete confirmation dialog. Handle the EditCanceling event to create a custom response to the cancel edit action.

Custom UI Elements

You can define the command column’s CellDisplayTemplate and HeaderTemplate to implement custom command elements. You can also create external command elements outside the Grid. Handle element click events and call the following methods:

StartEditNewRowAsync
Displays the edit row or form used to create a new data row.
StartEditRowAsync | StartEditDataItemAsync
Displays the edit row or form used to modify the specified row or data item.
SaveChangesAsync | CancelEditAsync
Saves or discards changes made in the edit form or edit row.
ShowRowDeleteConfirmation | ShowDataItemDeleteConfirmation
Displays the delete confirmation dialog for the specified row or data item.

View Example: Use icons instead of default command buttons View Example: Disable row editing depending on row values

2. Select and Set Up Edit Mode

Use the EditMode property to choose one of the following data edit modes:

EditForm (Default)
The Grid displays the edit form instead of the edited data row.
PopupEditForm
The Grid displays the edit form in a pop-up window.
EditRow
The Grid displays inline editors instead of the edited row.

For more information about edit modes, refer to the EditMode property description.

Edit Form and Popup Edit Form Modes

In EditForm and PopupEditForm modes, use the EditFormTemplate to define edit form content.

The default edit form shows only the predefined Save and Cancel buttons. You can disable the EditFormButtonsVisible option to hide the predefined Save and Cancel buttons and implement your own buttons. Note the following specifics:

Call the GetEditor(String) method to add an automatically generated column editor in the edit form template.

Note

If you place a templated component in the edit form template, ensure that you specify the Context parameter explicitly either for the Grid template or for the nested component. Otherwise, an error occurs.

The following code snippet uses the DxFormLayout component to create an edit form that displays DevExpress editors for all visible data columns:

<DxGrid Data="Data" ...>
    <Columns>
        <DxGridCommandColumn />
        <DxGridDataColumn FieldName="FirstName" />
        <DxGridDataColumn FieldName="LastName" />
        <DxGridDataColumn FieldName="Title" />
        <DxGridDataColumn FieldName="HireDate" />
    </Columns>
    <EditFormTemplate Context="editFormContext">
        <DxFormLayout>
            <DxFormLayoutItem Caption="First Name:">
                @editFormContext.GetEditor("FirstName")
            </DxFormLayoutItem>
            <DxFormLayoutItem Caption="Last Name:">
                @editFormContext.GetEditor("LastName")
            </DxFormLayoutItem>
            <DxFormLayoutItem Caption="Title:">
                @editFormContext.GetEditor("Title")
            </DxFormLayoutItem>
            <DxFormLayoutItem Caption="Hire Date:">
                @editFormContext.GetEditor("HireDate")
            </DxFormLayoutItem>
        </DxFormLayout>
    </EditFormTemplate>
</DxGrid>

Blazor Grid Edit Form Content

View Example: How to edit a row on a separate page

Edit Row Mode

In EditRow mode, the Grid automatically generates editors for columns based on their field data types. You can set the EditorRenderMode property to Integrated to render in-place editors that occupy entire cells.

<DxGrid Data="@products" EditMode="GridEditMode.EditRow" EditorRenderMode="GridEditorRenderMode.Integrated">
    <Columns>
        <DxGridCommandColumn />
        <DxGridDataColumn FieldName="FirstName" />
        <DxGridDataColumn FieldName="LastName" />
        <DxGridDataColumn FieldName="Title" />
        <DxGridDataColumn FieldName="HireDate" />
    </Columns>
</DxGrid>

Blazor Grid Edit Row

The edit row displays Save and Cancel buttons in the command column. To hide these buttons, use SaveButtonVisible and CancelButtonVisible properties.

You can use either a common DataColumnCellEditTemplate or a column CellEditTemplate to create custom content for an edit row.

Note

If you place a templated component in the edit row template, ensure that you specify the Context parameter explicitly either for the Grid template or for the nested component. Otherwise, an error occurs.

3. Save Changes and Reload Data

Handle the events listed below to process changes.

EditModelSaving

This event fires when a user submits the edit form or saves changes in the edit row, and validation succeeds. Handle this event to check user input and access permissions, and post changes to the underlying data source.

The event argument’s IsNew property identifies whether the edit model corresponds to a new or existing row.

DataItemDeleting
This event fires when a user confirms the row delete operation in the confirmation dialog. Handle this event to check user access permissions and delete the data item that corresponds to the row from the data source.

Reload Data

Grid data should be reloaded after you post updates to the data source in an EditModelSaving or DataItemDeleting event handler.

If you use a Server Mode data source, GridDevExtremeDataSource, or edit a bound data collection directly (for instance, use Add and Remove methods, access elements by indexes, etc.), the Grid refreshes its data after an event handler is executed.

If you post updates to the underlying service (such as a DbContext EF Core), change an instance of a field or property bound to the Data parameter. The Grid reloads its data in response to this change. The example below demonstrates this scenario.

<DxGrid Data="Data"
        CustomizeEditModel="OnCustomizeEditModel"
        EditModelSaving="OnEditModelSaving"
        DataItemDeleting="OnDataItemDeleting"
        KeyFieldName="EmployeeId">
        @* ... *@
</DxGrid>
@* ... *@
    void OnCustomizeEditModel(GridCustomizeEditModelEventArgs e) {
        if(e.IsNew) {
            var editModel = (Employee)e.EditModel;
            editModel.EmployeeId = Data.Count() + 1;
        }
    }

    async Task OnEditModelSaving(GridEditModelSavingEventArgs e) {
        var editModel = (Employee)e.EditModel;
        // Re-query a data item from the database.
        var dataItem = e.IsNew ? editModel : Northwind.Employees.Find(editModel.EmployeeId);
        // Assign changes from the edit model to the data item.
        if (dataItem != null) {
            dataItem.FirstName = editModel.FirstName;
            dataItem.LastName = editModel.LastName;
            dataItem.Title = editModel.Title;
            dataItem.HireDate = editModel.HireDate;
            dataItem.EmployeeId = editModel.EmployeeId;
            // Post changes to the database.
            if (e.IsNew)
                await Northwind.AddAsync(dataItem);
            await Northwind.SaveChangesAsync();
            // Reload the entire Grid.
            Data = await Northwind.Employees.ToListAsync();
        }
    }

    async Task OnDataItemDeleting(GridDataItemDeletingEventArgs e) {
        // Re-query a data item from the database.
        var dataItem = Northwind.Employees.Find((e.DataItem as Employee).EmployeeId);
        if (dataItem != null) {
            // Remove the data item from the database.
            Northwind.Remove(dataItem);
            await Northwind.SaveChangesAsync();
            // Reload the entire Grid.
            Data = await Northwind.Employees.ToListAsync();
        }
    }
    @* ... *@
}

View Example: How to post changes to an in-memory data source

4. Specify a Key Field

The Grid compares and identifies data items to ensure correct edit and delete operations. If your data object has a primary key, assign it to the KeyFieldName or KeyFieldNames property. Otherwise, the Grid uses the standard .NET value equality comparison to identify data items.

<DxGrid Data="Data"
        CustomizeEditModel="OnCustomizeEditModel"
        EditModelSaving="OnEditModelSaving"
        DataItemDeleting="OnDataItemDeleting"
        @* ... *@
    </EditFormTemplate>

Customize Auto-Generated Editors

The Grid generates and configures cell editors for individual columns based on associated data types. The component displays these cell editors in the edit row. You can display an automatically generated column editor in the edit or pop-up edit form.

You can declare an object that contains editor settings in the DxGridDataColumn.EditSettings property to customize the default editor or replace it with another editor. The table below lists classes that define cell editor settings and the corresponding data types:

Editor Settings Generated for Data Types Supported Data Types
DxCheckBoxSettings Boolean All data types
DxComboBoxSettings Enum All data types
DxDateEditSettings DateTime, DateTimeOffset DateTime, DateTimeOffset
DxMaskedInputSettings Never generated. Numeric, DateTime, DateTimeOffset, TimeSpan, String
DxMemoSettings Never generated. String
DxSpinEditSettings Numeric Numeric
DxTextBoxSettings String String
DxTimeEditSettings Never generated. TimeSpan, DateTime

If the editor does not support the associated data type, the Grid replaces it with a read-only text box.

The code sample below demonstrates how to customize settings of an automatically generated spin editor.

<DxGrid Data="@products" ShowFilterRow="true" EditMode="GridEditMode.EditRow">
    <Columns>
        <DxGridCommandColumn />
        <DxGridDataColumn FieldName="ProductID" >
            <EditSettings>
                <DxSpinEditSettings ShowSpinButtons="false" ReadOnly="true" NullText="Type the ID" />
            </EditSettings>
        </DxGridDataColumn>
        <DxGridDataColumn FieldName="ProductName" />
        <DxGridDataColumn FieldName="UnitPrice" />
        <DxGridDataColumn FieldName="UnitsInOrder" />
    </Columns>
</DxGrid>

At runtime, handle the CustomizeDataRowEditor event to customize editors in the edit row. Call the GetColumnEditSettings method to access and customize editor settings.

Initialize New Rows

Follow the steps below to display predefined values in data editors when a user adds a new row:

  1. Handle the CustomizeEditModel event.
  2. Check the event argument’s IsNew property to identify new rows.
  3. Use the EditModel property to access the edit model and initialize model field values.

The following snippet specifies the predefined value for the HireDate field:

<DxGrid Data="GridDataSource"
        EditModelSaving="OnEditModelSaving"
        DataItemDeleting="OnDataItemDeleting"
        KeyFieldName="EmployeeId"
        CustomizeEditModel="Grid_CustomizeEditModel">
        @* ... *@
</DxGrid>

@code {
    IEnumerable<object> GridDataSource { get; set; }
    @* ... *@
    async Task Grid_CustomizeEditModel(GridCustomizeEditModelEventArgs e) {
        if (e.IsNew) {
            var editModel = (Employee)e.EditModel;
            editModel.HireDate = DateTime.Today;
        }
    }
    @* ... *@
}

Create a Custom Edit Model

The Grid cannot generate an edit model in the following cases:

  • A data item class does not have a parameterless constructor.
  • Data item fields bound to Grid columns are read-only.

Handle the CustomizeEditModel event to create a custom edit model or customize the model generated automatically based on the bound data item. Use the event argument’s DataItem property to access this data item. Assign your custom edit model to the event argument’s EditModel property.

In an EditModelSaving event handler and the EditFormTemplate, cast the EditModel property value to your custom edit model class.

<DxGrid Data="GridDataSource"
        EditModelSaving="OnEditModelSaving"
        DataItemDeleting="OnDataItemDeleting"
        KeyFieldName="EmployeeId"
        CustomizeEditModel="Grid_CustomizeEditModel">
    <Columns>
    @* ... *@
    </Columns>
    <EditFormTemplate Context="editFormContext">
    @* ... *@
    </EditFormTemplate>
</DxGrid>

@code {
    IEnumerable<object> GridDataSource { get; set; }
    @* ... *@
    class EmployeeEditModel {
        public int? EmployeeId { get; set; }
        [Required, MaxLength(64)]
        public string LastName { get; set; }
        [Required, MaxLength(64)]
        public string FirstName { get; set; }
        public string Title { get; set; }
        public DateTime? HireDate { get; set; }
    }

    async Task OnEditModelSaving(GridEditModelSavingEventArgs e) {
        var editModel = (EmployeeEditModel)e.EditModel;
        @* ... *@
    }
    @* ... *@
    async Task Grid_CustomizeEditModel(GridCustomizeEditModelEventArgs e) {
        var dataItem = (Employee)e.DataItem;
        if (dataItem == null)
            e.EditModel = new EmployeeEditModel { };
        else {
            e.EditModel = new EmployeeEditModel {
                EmployeeId = dataItem.EmployeeId,
                FirstName = dataItem.FirstName,
                LastName = dataItem.LastName,
                Title = dataItem.Title,
                HireDate = dataItem.HireDate
            };
        }
    }
    @* ... *@
}

View Example: Display an error message from the Web API Service

View Example: Create and edit unbound columns

Edit Data with Nested Properties

When you edit data, the Grid clones a bound data item – namely creates an object of the same type and copies all property values into it. If a property is of a reference type, the reference is copied but the referred object is not copied. As the result, the original object and its clone refer to the same object.

To edit nested objects, create a copy of these objects manually (make a deep copy of the original data item object). You can use the following approaches to implement a deep copy operation:

  • Handle the CustomizeEditModel event, clone the nested object, and assign it to field whose value is the reference type.

    void OnCustomizeEditModel(GridCustomizeEditModelEventArgs obj) {
        var customer = (Customer)obj.EditModel;
        customer.Address = customer.Address?.Clone() ?? new Address();
    }
    
    public class Person {
        public int ID { get; set; }
        public string FirstName {get; set;}
        public string LastName { get; set; }
        public Address Address { get; set; }
    }
    public class Address {
        public string StreetLine1 { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public int ZipCode { get; set; }
        public Address Clone() {
            return (Address) MemberwiseClone();
        }
    }
    
  • Create constructors for the data item type and the nested object’s type. In the data item type constructor, the nested object type constructor clones the nested object with its property values. Handle the CustomizeEditModel event and call a data item’s class constructor to initialize the edit model.

    void OnCustomizeEditModel(GridCustomizeEditModelEventArgs e) {
        e.EditModel = new Person((Person)e.DataItem);
    }
    
    public Person(Person person) {
        this.ID = person.ID;
        this.FirstName = person.FirstName;
        this.LastName = person.LastName;
        this.Address = new Address(person.Address); 
    }
    public Address(Address address) {
        this.StreetLine1 = address.StreetLine1;
        this.City = address.City;
        this.State = address.State;
        this.ZipCode = address.ZipCode;
    }