What is a Data Grid?

A Data Grid is a UI component that displays and manipulates tabular data. Unlike a standard HTML table, which is static and requires manual work for every interaction, a Data Grid provides sorting, filtering, paging, and inline editing out of the box.

Think of the difference between a printed spreadsheet and a live Excel file. One is read-only; the other lets you search, sort, filter, and edit in place. A Data Grid brings that same interactive experience to the browser.

Why DevExpress MVC Data Grid?

The DevExpress MVC GridView is an enterprise-grade component built for real business applications. It handles millions of rows through server-mode binding, supports master-detail relationships for parent-child data, and provides batch editing so users can modify multiple rows and save everything in a single request. These are not theoretical features; they are the building blocks of systems like invoice management, warehouse tracking, and financial reporting.

In this guide, we will build one such system step by step. Each section adds a new capability, and each includes a live, interactive grid so you can see the feature working in your browser right now.


The Scenario: Invoice Management System

We are building an Invoice Management System. It handles three types of documents: Sales Invoices, Credit Notes, and Rental Invoices. Each invoice belongs to a company, has a date and total amount, and can contain one or more line items (the individual products or services being billed). By the end of this guide, the grid will support filtering, master-detail drill-down, inline editing, and data export.


Step 1: The Humble HTML Table

Every web developer starts here. A plain HTML <table> can display data, but it does nothing beyond that. There is no sorting, no filtering, no paging. If you have 10,000 invoices, they all render at once. If a user wants to find a specific company, they have to scroll manually or rely on the browser's Ctrl+F. Adding any of these features means writing custom JavaScript, managing state, and handling edge cases around pagination and URL parameters.

Below is the same invoice data rendered in a plain table. It looks fine for four rows, but imagine this with hundreds.

Invoice # Type Company Date Total Status
INV-001 Sales Invoice Tech Solutions Ltd 5/29/2026 $1,500.00 Paid
CRN-001 Credit Note Global Trade Co 5/31/2026 ($250.00) Processed
RNL-001 Rental Invoice Urban Living 6/2/2026 $3,200.00 Pending
INV-002 Sales Invoice Pioneer Systems 6/3/2026 $450.00 Paid

This table is a dead end. To add sorting alone, you would need JavaScript event handlers on every column header, a comparison function for each data type (string, date, currency), and logic to re-render the rows. Paging would require tracking the current page index, slicing the data, and rendering navigation controls. The DevExpress GridView handles all of this with a few lines of configuration.


Step 2: Transitioning to DevExpress GridView

The first step is replacing that HTML table with a DevExpress GridView. At this stage we are not adding any advanced features. We simply define the columns, point the grid at our data, and let the component handle rendering.

The grid needs three things: a Model class that describes the shape of the data, a Controller action that fetches the data and returns a partial view, and a Razor partial view that configures the grid columns and binds the model.

public class Invoice
{
    public int ID { get; set; }
    public string InvoiceNumber { get; set; }
    public string Type { get; set; }
    public string CompanyName { get; set; }
    public string Address { get; set; }
    public DateTime Date { get; set; }
    public decimal TotalAmount { get; set; }
    public string Status { get; set; }
}
@model List<Invoice>

@Html.DevExpress().GridView(settings => {
    settings.Name = "gvInvoicesBasic";
    settings.KeyFieldName = "ID";
    settings.CallbackRouteValues = new {
        Controller = "DevExpress",
        Action = "InvoicesBasicGridPartial"
    };
    settings.Width = Unit.Percentage(100);

    settings.Columns.Add("InvoiceNumber");
    settings.Columns.Add("Type");
    settings.Columns.Add("CompanyName");
    settings.Columns.Add("Date").PropertiesEdit.DisplayFormatString = "d";
    settings.Columns.Add("TotalAmount").PropertiesEdit.DisplayFormatString = "c";
    settings.Columns.Add("Status");

}).Bind(Model).GetHtml()
[ValidateInput(false)]
public ActionResult InvoicesBasicGridPartial()
{
    return PartialView("_InvoicesBasicGridPartial", GetInvoices());
}

private List<Invoice> GetInvoices()
{
    if (Session["Invoices"] == null)
    {
        Session["Invoices"] = new List<Invoice>
        {
            new Invoice {
                ID = 1,
                InvoiceNumber = "INV-001",
                Type = "Sales Invoice",
                CompanyName = "Tech Solutions Ltd",
                Date = DateTime.Today.AddDays(-5),
                TotalAmount = 1500.00m,
                Status = "Paid"
            },
            // ... more invoices
        };
    }
    return (List<Invoice>)Session["Invoices"];
}

The Live Result

Invoice Number 
Type 
Company Name 
Date 
Total Amount 
Status 
INV-001Sales InvoiceTech Solutions Ltd5/29/2026$1,500.00Paid
CRN-001Credit NoteGlobal Trade Co5/31/2026($250.00)Processed
RNL-001Rental InvoiceUrban Living6/2/2026$3,200.00Pending
INV-002Sales InvoicePioneer Systems6/3/2026$450.00Paid
Try it: Click any column header to sort the data. That is built-in behaviour; no extra code required. Compare that to the static HTML table above, which does nothing when you click on it.

With roughly 15 lines of Razor configuration, we have a professional grid with automatic column rendering, currency and date formatting, and click-to-sort. The Controller action is a simple pass-through that fetches the data from the session and returns a partial view. This separation of concerns (Model, View, Controller) is the foundation of every DevExpress MVC grid.


Step 3: Paging, Filtering, and Search

A grid that only sorts is not enough for production use. When you have hundreds or thousands of invoices, users need to narrow down what they see. DevExpress provides three tools for this: a pager that breaks data into pages, a filter row that lets users type a value at the top of any column, and a search panel that searches across all columns at once.

These features are enabled purely through configuration. No custom JavaScript, no extra controller logic. The grid handles the filtering and paging on the server automatically via AJAX callbacks.

Three new settings are added to the grid configuration:

1. PageSize controls how many rows appear per page
2. ShowFilterRow adds a text input above each column
3. SettingsSearchPanel.Visible adds a global search box

The model and controller remain identical to Step 2.
No server-side filtering code is needed; DevExpress
handles it internally through its callback mechanism.
@Html.DevExpress().GridView(settings => {
    settings.Name = "gvInvoicesFilter";
    settings.KeyFieldName = "ID";
    settings.CallbackRouteValues = new {
        Controller = "DevExpress",
        Action = "InvoicesFilterGridPartial"
    };
    settings.Width = Unit.Percentage(100);

    settings.Columns.Add("InvoiceNumber");
    settings.Columns.Add("Type");
    settings.Columns.Add("CompanyName");
    settings.Columns.Add("Date").PropertiesEdit.DisplayFormatString = "d";
    settings.Columns.Add("TotalAmount").PropertiesEdit.DisplayFormatString = "c";
    settings.Columns.Add("Status");

    // Paging
    settings.SettingsPager.PageSize = 10;

    // Filtering
    settings.Settings.ShowFilterRow = true;
    settings.SettingsSearchPanel.Visible = true;

    // Row focus
    settings.SettingsBehavior.AllowFocusedRow = true;

}).Bind(Model).GetHtml()
[ValidateInput(false)]
public ActionResult InvoicesFilterGridPartial()
{
    return PartialView("_InvoicesFilterGridPartial", GetInvoices());
}

// The controller action is identical in structure to Step 2.
// DevExpress handles filtering and paging internally.
// The grid sends AJAX callbacks to this action, passing
// filter and page parameters automatically.

The Live Result

x
Invoice Number 
Type 
Company Name 
Date 
Total Amount 
Status 
INV-001Sales InvoiceTech Solutions Ltd5/29/2026$1,500.00Paid
CRN-001Credit NoteGlobal Trade Co5/31/2026($250.00)Processed
RNL-001Rental InvoiceUrban Living6/2/2026$3,200.00Pending
INV-002Sales InvoicePioneer Systems6/3/2026$450.00Paid
Try it: Type "Sales" in the filter row above the Type column to narrow the results. Use the search box in the top-right to search across all columns. Click a row to focus it.

The filter row supports different matching modes depending on the column type. Text columns default to "Contains" matching, date columns provide a date picker, and numeric columns support range comparisons. All of this is handled by the DevExpress framework without any additional code on your part.


Step 4: Master-Detail Relationships

Most real-world data is relational. An invoice (the master record) contains one or more line items (the detail records). Rather than navigating to a separate page for each invoice's items, a master-detail grid lets users expand a row in place and see its child records directly.

DevExpress supports this through a detail row template. When a user clicks the expand icon next to a row, the grid calls a separate controller action to fetch the child data and renders it inside a nested grid. The child grid is a fully independent component with its own columns, formatting, and summary footer.

public class InvoiceLine
{
    public int ID { get; set; }
    public int InvoiceID { get; set; }
    public string Description { get; set; }
    public int Quantity { get; set; }
    public decimal UnitPrice { get; set; }
    public decimal LineTotal => Quantity * UnitPrice;
}

// The LineTotal property is computed, not stored.
// DevExpress reads it like any other property and
// can include it in summaries and exports.
// Added to the master grid settings:

settings.SettingsDetail.ShowDetailRow = true;

settings.SetDetailRowTemplateContent(c => {
    Html.RenderAction("InvoiceLinesGridPartial", new {
        invoiceId = DataBinder.Eval(c.DataItem, "ID")
    });
});

// When the user expands a row, DevExpress calls
// InvoiceLinesGridPartial with the invoice's ID.
// The detail grid renders inside the expanded row.
[ValidateInput(false)]
public ActionResult InvoicesMasterDetailGridPartial()
{
    return PartialView(
        "_InvoicesMasterDetailGridPartial",
        GetInvoices()
    );
}

[ValidateInput(false)]
public ActionResult InvoiceLinesGridPartial(int invoiceId)
{
    ViewBag.InvoiceID = invoiceId;
    return PartialView(
        "_InvoiceLinesGridPartial",
        GetInvoiceLines(invoiceId)
    );
}

private List<InvoiceLine> GetInvoiceLines(int invoiceId)
{
    var lines = new List<InvoiceLine>();
    if (invoiceId == 1)
    {
        lines.Add(new InvoiceLine {
            ID = 1, InvoiceID = 1,
            Description = "Web Development Service",
            Quantity = 1, UnitPrice = 1000.00m
        });
        lines.Add(new InvoiceLine {
            ID = 2, InvoiceID = 1,
            Description = "UI/UX Design",
            Quantity = 5, UnitPrice = 100.00m
        });
    }
    return lines;
}

The Live Result

x
Invoice Number 
Type 
Company Name 
Date 
Total Amount 
Status 
 
ExpandINV-001Sales InvoiceTech Solutions Ltd5/29/2026$1,500.00Paid
ExpandCRN-001Credit NoteGlobal Trade Co5/31/2026($250.00)Processed
ExpandRNL-001Rental InvoiceUrban Living6/2/2026$3,200.00Pending
ExpandINV-002Sales InvoicePioneer Systems6/3/2026$450.00Paid
Try it: Click the expand icon (the small arrow) next to INV-001 or RNL-001 to see their line items. The nested grid shows a summary footer with the line total. INV-002 and CRN-001 have no line items, so their detail row will be empty.

Each nested grid is a complete DevExpress GridView with its own callback route. This means you could add paging, filtering, or editing to the detail grid independently. The parent and child grids communicate only through the invoice ID passed in the expand callback.


Step 5: Batch Editing

Traditional web forms force users to edit one record at a time: click an edit button, modify values, save, go back, repeat. For data-heavy workflows like invoice management, this is painfully slow. Batch editing turns the grid into something closer to a spreadsheet. Users click a cell to edit it, tab to the next cell, make all their changes, and then save everything in a single request.

DevExpress tracks all modifications client-side. Changed cells are highlighted in green. Deleted rows are marked in red. New rows appear at the top. When the user clicks Save, the grid sends all inserts, updates, and deletes to the server in one POST request, packaged in a MVCxGridViewBatchUpdateValues object.

Batch editing requires three additions:

1. View: Set the editing mode to Batch and configure
   permissions (AllowEdit, AllowInsert, AllowDelete).
   Add a CommandColumn for the New and Delete buttons.
   Set ShowStatusBar to display the Save/Cancel bar.

2. Controller: Add a new action that accepts
   MVCxGridViewBatchUpdateValues. This object contains
   three collections: Insert, Update, and DeleteKeys.

3. Route: Set BatchUpdateRouteValues on the grid
   to point to the new controller action.
// Added to the grid settings:

settings.SettingsEditing.Mode = GridViewEditingMode.Batch;
settings.SettingsEditing.BatchEditSettings.EditMode
    = GridViewBatchEditMode.Cell;
settings.SettingsEditing.BatchEditSettings.StartEditAction
    = GridViewBatchStartEditAction.Click;
settings.SettingsEditing.BatchUpdateRouteValues = new {
    Controller = "DevExpress",
    Action = "InvoicesBatchUpdate"
};

settings.SettingsDataSecurity.AllowEdit = true;
settings.SettingsDataSecurity.AllowInsert = true;
settings.SettingsDataSecurity.AllowDelete = true;
settings.Settings.ShowStatusBar = GridViewStatusBarMode.Visible;

settings.CommandColumn.Visible = true;
settings.CommandColumn.ShowNewButtonInHeader = true;
settings.CommandColumn.ShowDeleteButton = true;
[HttpPost, ValidateInput(false)]
public ActionResult InvoicesBatchUpdate(
    MVCxGridViewBatchUpdateValues<Invoice, int> updateValues)
{
    var model = GetInvoices();

    // Process new rows
    foreach (var item in updateValues.Insert)
    {
        if (updateValues.IsValid(item))
        {
            item.ID = model.Max(x => x.ID) + 1;
            model.Add(item);
        }
    }

    // Process modified rows
    foreach (var item in updateValues.Update)
    {
        if (updateValues.IsValid(item))
        {
            var target = model.FirstOrDefault(x => x.ID == item.ID);
            if (target != null)
            {
                target.InvoiceNumber = item.InvoiceNumber;
                target.CompanyName = item.CompanyName;
                target.Status = item.Status;
            }
        }
    }

    // Process deleted rows
    foreach (var id in updateValues.DeleteKeys)
    {
        var target = model.FirstOrDefault(x => x.ID == id);
        if (target != null) model.Remove(target);
    }

    return PartialView("_InvoicesGridPartial", model);
}

The Live Result

New
Invoice Number 
Type 
Company Name 
Date 
Total Amount 
Status 
  
Inserted values
Updated values
Deleted values
ExpandDeleteINV-001Sales InvoiceTech Solutions Ltd5/29/2026$1,500.00Paid
ExpandDeleteCRN-001Credit NoteGlobal Trade Co5/31/2026($250.00)Processed
ExpandDeleteRNL-001Rental InvoiceUrban Living6/2/2026$3,200.00Pending
ExpandDeleteINV-002Sales InvoicePioneer Systems6/3/2026$450.00Paid
Preview changes
Save changes
Cancel changes
Try it: Click any cell to edit its value. The cell turns green to indicate a pending change. Click the New button in the header to add a row. Click the red X to mark a row for deletion. When you are done, click Save Changes in the status bar at the bottom to submit everything to the server in a single request.

Batch editing is particularly valuable in scenarios where users need to update many records quickly, such as adjusting invoice statuses at month-end or correcting bulk data imports. The single round-trip to the server means better performance and a smoother user experience compared to row-by-row editing.


Step 6: Summaries, Aggregates, and Final Polish

A production grid needs more than just data display and editing. Users expect footer totals, row counts, and the ability to export what they see to a spreadsheet or PDF. DevExpress provides summary aggregates (sum, count, average, min, max) that render in the grid footer, and a server-side export API that produces formatted Excel, PDF, CSV, and RTF files.

The grid below combines every feature from the previous steps: sorting, filtering, search, master-detail, batch editing, summary totals, and row counts. This is the complete invoice management grid.

Two additions for this final step:

1. Footer summaries: ShowFooter = true, then add
   TotalSummary items for Sum and Count aggregates.
   These update automatically when data changes.

2. Export: DevExpress provides GridViewExtension export
   methods (ExportToXlsx, ExportToPdf, ExportToCsv).
   Each takes the grid settings and data, and returns
   an ActionResult that downloads the file.

   Supported formats: XLS, XLSX, PDF, RTF, CSV, DOCX
// Footer summaries
settings.Settings.ShowFooter = true;

settings.TotalSummary.Add(
    DevExpress.Data.SummaryItemType.Sum,
    "TotalAmount"
).DisplayFormat = "Total: {0:c}";

settings.TotalSummary.Add(
    DevExpress.Data.SummaryItemType.Count,
    "InvoiceNumber"
).DisplayFormat = "{0} invoices";

// Export is handled server-side:
// GridViewExtension.ExportToXlsx(settings, data);
// GridViewExtension.ExportToPdf(settings, data);
// GridViewExtension.ExportToCsv(settings, data);
// Export action example:
public ActionResult ExportInvoicesToPdf()
{
    var settings = new GridViewSettings();
    settings.Name = "gvInvoicesExport";
    settings.Columns.Add("InvoiceNumber");
    settings.Columns.Add("Type");
    settings.Columns.Add("CompanyName");
    settings.Columns.Add("Date")
        .PropertiesEdit.DisplayFormatString = "d";
    settings.Columns.Add("TotalAmount")
        .PropertiesEdit.DisplayFormatString = "c";
    settings.Columns.Add("Status");

    return GridViewExtension.ExportToPdf(
        settings,
        GetInvoices()
    );
}

// Each format has its own method:
// ExportToXlsx, ExportToPdf, ExportToCsv, etc.
// The exported file respects column formatting,
// visibility, and sort order.

The Live Result

x
New
Invoice Number 
Type 
Company Name 
Date 
Total Amount 
Status 
  
Inserted values
Updated values
Deleted values
ExpandDeleteINV-001Sales InvoiceTech Solutions Ltd5/29/2026$1,500.00Paid
ExpandDeleteCRN-001Credit NoteGlobal Trade Co5/31/2026($250.00)Processed
ExpandDeleteRNL-001Rental InvoiceUrban Living6/2/2026$3,200.00Pending
ExpandDeleteINV-002Sales InvoicePioneer Systems6/3/2026$450.00Paid
 
Preview changes
Save changes
Cancel changes

Export to Excel, PDF, or CSV

Click the buttons below to download the invoice data in different formats. The exported file respects column formatting, visibility, and sort order.

Try it: Click any export button above to download the invoice data. Look at the footer row for the invoice count and total amount. Expand a row to see line items with their own total. Edit values and watch the grid track your changes.

From summaries and aggregates in the footer to responsive layouts that adapt to smaller screens, the DevExpress GridView is designed to grow with your application. Every feature we have covered (sorting, filtering, master-detail, batch editing, summaries, export) works together without conflict, because the component was designed as a cohesive system rather than a collection of add-ons.


Step 7: Inline Row Editing (Edit/Update/Cancel)

Inline editing is the classic approach where each row has Edit and Delete buttons. When a user clicks Edit, the row transforms into an editable form with input controls. After making changes, the user clicks Update to save or Cancel to discard. This is ideal when you want to control changes one row at a time.

The grid below demonstrates inline editing with specialized column editors: ComboBox for categories, SpinEdit for numeric values, DateEdit for dates, and CheckBox for boolean fields.

Inline editing requires three settings:

1. Mode = GridViewEditingMode.Inline
2. CommandColumn with ShowEditButton and ShowDeleteButton
3. UpdateRouteValues pointing to a controller action
   that accepts MVCxGridViewInlineUpdateValues

Each row gets its own Edit/Update/Cancel buttons.
Only one row can be in edit mode at a time.
// View configuration:
settings.SettingsEditing.Mode = GridViewEditingMode.Inline;
settings.SettingsEditing.UpdateRouteValues = new {
    Controller = "DevExpress",
    Action = "ProductsInlineUpdate"
};
settings.SettingsBehavior.ConfirmDelete = true;

settings.CommandColumn.Visible = true;
settings.CommandColumn.ShowNewButton = true;
settings.CommandColumn.ShowEditButton = true;
settings.CommandColumn.ShowDeleteButton = true;

// Column with ComboBox editor:
settings.Columns.Add(column => {
    column.FieldName = "Category";
    column.ColumnType = MVCxGridViewColumnType.ComboBox;
    var props = column.PropertiesEdit as ComboBoxProperties;
    props.DataSource = GetCategories();
    props.TextField = "Name";
    props.ValueField = "Name";
});
[HttpPost]
public ActionResult ProductsInlineUpdate(
    MVCxGridViewInlineUpdateValues<Product, int> values)
{
    var model = GetProducts();

    foreach (var item in values)
    {
        if (values.IsValid(item))
        {
            if (item.ID == 0) // New record
            {
                item.ID = model.Max(x => x.ID) + 1;
                model.Add(item);
            }
            else // Update existing
            {
                var target = model.FirstOrDefault(
                    x => x.ID == item.ID);
                if (target != null)
                {
                    target.Name = item.Name;
                    target.Price = item.Price;
                    // ... update other fields
                }
            }
        }
    }
    return PartialView("_ProductsGridPartial", model);
}

The Live Result

x
# 
Product Name 
Category 
Price 
Stock Level 
Active 
Created 
 
xv
x
+
-
x
+
-
xv
xv
EditNewDeleteLaptop Pro 15"Electronics1299.99453/5/2026
EditNewDeleteWireless MouseAccessories29.992304/4/2026
EditNewDeleteUSB-C HubAccessories59.991204/19/2026
EditNewDeleteMechanical KeyboardElectronics149.99785/4/2026
EditNewDeleteMonitor 27" 4KElectronics499.99325/14/2026
EditNewDeleteWebcam HDAccessories79.99955/19/2026
EditNewDeleteDesk Chair ErgonomicFurniture349.99185/24/2026
EditNewDeleteStanding DeskFurniture599.99125/29/2026
Try it: Click the Edit button on any row. The row transforms into input fields with dropdowns, spin editors, and date pickers. Make changes and click Update (green check) or Cancel (red X). Click the New button in the header to add a product.

Step 8: Edit Form Mode (Popup Form Editing)

Instead of editing rows inline, Edit Form mode opens a dedicated form (either inline or in a popup) for data entry. This provides more space for complex forms, better layout control, and a focused editing experience. It's ideal when records have many fields or when you need validation before saving.

This grid demonstrates advanced column types: ComboBox with incremental filtering, DateEdit with calendar controls, SpinEdit with currency formatting, and CheckBox for boolean values.

Edit Form mode uses:

1. Mode = GridViewEditingMode.EditForm
2. EditFormLayoutProperties.ColCount for layout
3. MVCxGridViewEditFormUpdatingValues in controller

The form appears when user clicks Edit or New.
This approach works well with validation rules
and complex data entry scenarios.
// View configuration:
settings.SettingsEditing.Mode = GridViewEditingMode.EditForm;
settings.SettingsEditing.EditFormLayoutProperties.ColCount = 2;

// ComboBox with filtering:
settings.Columns.Add(column => {
    column.FieldName = "Department";
    column.ColumnType = MVCxGridViewColumnType.ComboBox;
    var props = column.PropertiesEdit as ComboBoxProperties;
    props.DataSource = departments;
    props.IncrementalFilteringMode = 
        IncrementalFilteringMode.StartsWith;
});

// DateEdit with calendar:
settings.Columns.Add(column => {
    column.FieldName = "HireDate";
    column.ColumnType = MVCxGridViewColumnType.DateEdit;
    var props = column.PropertiesEdit as DateEditProperties;
    props.DisplayFormatString = "d";
    props.CalendarProperties.ShowTodayButton = true;
});
[HttpPost]
public ActionResult EmployeesEditFormUpdate(
    MVCxGridViewEditFormUpdatingValues<Employee> values)
{
    var model = GetEmployees();

    // Handle new record
    if (values.NewItemRowItem != null && values.IsValid)
    {
        values.NewItemRowItem.ID = model.Max(x => x.ID) + 1;
        model.Add(values.NewItemRowItem);
    }

    // Handle update
    if (values.UpdateItem != null && values.IsValid)
    {
        var target = model.FirstOrDefault(
            x => x.ID == values.UpdateItem.ID);
        // ... copy properties
    }

    // Handle delete
    if (values.DeleteItem != null)
    {
        var target = model.FirstOrDefault(
            x => x.ID == values.DeleteItem.ID);
        if (target != null) model.Remove(target);
    }

    return PartialView("_EmployeesGridPartial", model);
}

The Live Result

x
# 
First Name 
Last Name 
Department 
Job Title 
Hire Date 
Salary 
Performance (0-100) 
Full-Time 
 
xv
xv
x
+
-
x
+
-
xv
EditNewDeleteJohnSmithEngineeringSenior Developer6/3/20219500092
EditNewDeleteSarahJohnsonMarketingMarketing Manager6/3/20237800088
EditNewDeleteMikeDavisEngineeringJunior Developer6/3/20256200075
EditNewDeleteEmilyBrownHRHR Specialist6/3/20226800085
EditNewDeleteDavidWilsonSalesSales Representative6/3/20245500078
EditNewDeleteLisaTaylorEngineeringTech Lead6/3/202011500096
Try it: Click Edit on any employee row. A form appears with all fields laid out in two columns. Use the dropdown for Department, the calendar for HireDate, spin editors for Salary and Performance Score. Notice the incremental filtering on the Department dropdown—type "Eng" to see it filter.

Step 9: Grouping and Summary Features

DevExpress GridView supports powerful data grouping out of the box. Users can drag any column header to the group panel to organize data hierarchically. Combined with group summaries and total summaries, this transforms raw data into actionable insights without writing any aggregation code.

This example demonstrates: grouping by multiple columns, group-level summaries (count, average, sum), total footer summaries, custom column templates with color-coded badges, ProgressBar columns, conditional row highlighting, and advanced column formatting.

Grouping and Summaries include:

1. Group by any column (drag header to group panel)
2. Multiple group levels (group by Project, then Priority)
3. Group summaries: Count, Average, Sum per group
4. Total summaries: Footer row with aggregates
5. Custom column templates: Color-coded badges
6. ProgressBar columns for percentage values
7. Conditional row highlighting (overdue tasks)
8. ComboBox columns with predefined values
// Enable grouping:
settings.SettingsBehavior.AllowGroup = true;
settings.SettingsBehavior.AutoExpandAllGroups = true;

// Group summaries:
settings.GroupSummary.Add(
    DevExpress.Data.SummaryItemType.Count, 
    "TaskName"
).DisplayFormat = "Tasks: {0}";

settings.GroupSummary.Add(
    DevExpress.Data.SummaryItemType.Average, 
    "Progress"
).DisplayFormat = "Avg Progress: {0:P0}";

// Total summaries:
settings.TotalSummary.Add(
    DevExpress.Data.SummaryItemType.Count, 
    "TaskName"
).DisplayFormat = "Total Tasks: {0}";

settings.TotalSummary.Add(
    DevExpress.Data.SummaryItemType.Sum, 
    "EstimatedHours"
).DisplayFormat = "Total: {0} hrs";

// Initial grouping:
settings.GroupBy(summary => {
    summary.Add("Project", ColumnSortOrder.Ascending);
    summary.Add("Priority", ColumnSortOrder.Ascending);
});
Possibilities with grouping:

- Drag/drop columns to group panel by users
- Collapse/expand groups individually
- Custom group headers with templates
- Multiple summaries per group
- Conditional formatting (highlight overdue rows)
- Export grouped data to Excel/PDF
- Combine with filtering and search
- Works with master-detail and editing

The grid below auto-groups by Project and Priority.
Try dragging the AssignedTo column header to the
group panel to add a third grouping level.

The Live Result

x
Task 
Assigned To 
Status 
Progress 
Due Date 
Est. Hours 
  
xv
CollapseProject: CRM System (Tasks: 4, Avg Progress: 5,250%, Total Hours: 77)
 CollapsePriority: High (Tasks: 2, Avg Progress: 8,250%, Total Hours: 32)
  Design Database SchemaJohn SmithCompleted
100%
5/24/202612.0
  Create API EndpointsJohn SmithIn Progress
65%
6/8/202620.0
 CollapsePriority: Medium (Tasks: 2, Avg Progress: 2,250%, Total Hours: 45)
  Build UI ComponentsLisa TaylorIn Progress
45%
6/13/202630.0
  Write Unit TestsMike DavisNot Started
0%
6/18/202615.0
CollapseProject: HR System (Tasks: 1, Avg Progress: 1,000%, Total Hours: 18)
 CollapsePriority: Medium (Tasks: 1, Avg Progress: 1,000%, Total Hours: 18)
  Employee Onboarding PortalEmily BrownNot Started
10%
6/28/202618.0
CollapseProject: Marketing Website (Tasks: 2, Avg Progress: 1,500%, Total Hours: 18)
 CollapsePriority: Low (Tasks: 1, Avg Progress: 3,000%, Total Hours: 8)
  SEO OptimizationSarah JohnsonIn Progress
30%
6/15/20268.0
 CollapsePriority: Medium (Tasks: 1, Avg Progress: 0%, Total Hours: 10)
  Content CreationSarah JohnsonNot Started
0%
6/23/202610.0
CollapseProject: Sales Dashboard (Tasks: 1, Avg Progress: 5,000%, Total Hours: 6)
 CollapsePriority: High (Tasks: 1, Avg Progress: 5,000%, Total Hours: 6)
  Sales Pipeline ReviewDavid WilsonIn Progress
50%
6/10/20266.0
Try it: Notice the grouped rows with group headers showing task count, average progress, and total hours. Collapse/expand groups with the arrow icon. Overdue tasks are highlighted in red. Drag the "Assigned To" column to the group panel to create nested groups.

Step 10: Selection and Multi-Select Features

Many business scenarios require users to select multiple records for batch processing—sending emails, updating statuses, generating reports, or exporting selected data. DevExpress provides flexible selection modes: checkbox-based selection, row-click selection, and single-select mode.

This example demonstrates: checkbox column with "select all" on page, row-click selection, client-side selection events, server-side processing of selected records, and display of selected items.

Selection features include:

1. Checkbox column in command column
2. Select All checkbox (per page or all rows)
3. Row-click selection (click to toggle)
4. Single-select mode option
5. Client-side GetSelectedKeysOnPage()
6. Server-side processing via POST
7. Display selected items in detail view
8. Combine with other grid features
// Enable selection:
settings.SettingsBehavior.AllowSelectByRowClick = true;
settings.SettingsBehavior.AllowSelectSingleRowOnly = false;

// Checkbox column:
settings.CommandColumn.Visible = true;
settings.CommandColumn.ShowSelectCheckbox = true;
settings.CommandColumn.SelectAllCheckboxMode = 
    GridViewSelectAllCheckboxMode.Page;

// Client-side event:
settings.ClientSideEvents.SelectionChanged = 
    "onProductSelectionChanged";
// JavaScript to handle selection:
function onProductSelectionChanged(s, e) {
    var selectedKeys = s.GetSelectedKeysOnPage();
    document.getElementById('selectedCount')
        .textContent = selectedKeys.length;
}

function processSelectedProducts() {
    var grid = gvProductSelection;
    var selectedKeys = grid.GetSelectedKeysOnPage();
    
    $.ajax({
        url: '/DevExpress/ProcessSelectedProducts',
        type: 'POST',
        data: { selectedIds: selectedKeys },
        traditional: true,
        success: function(data) {
            $('#selectedItemsResult').html(data);
        }
    });
}

The Live Result

x
Product Name 
Category 
Price 
Stock Level 
Active 
Created 
 
xv
Laptop Pro 15"Electronics$1,299.99453/5/2026
Wireless MouseAccessories$29.992304/4/2026
USB-C HubAccessories$59.991204/19/2026
Mechanical KeyboardElectronics$149.99785/4/2026
Monitor 27" 4KElectronics$499.99325/14/2026
Webcam HDAccessories$79.99955/19/2026
Desk Chair ErgonomicFurniture$349.99185/24/2026
Standing DeskFurniture$599.99125/29/2026
Selected Items: 0 product(s) selected
Try it: Click the checkbox in the header row to select all products on the current page. Or click individual rows to select them. Watch the counter update in real-time. Click "Process Selected Products" to see the selected items displayed in a table below.

Step 11: Adaptive Grid Layout (Responsive Design)

On desktop screens, a grid with many columns looks great. On tablets and phones, those same columns create a horizontal scroll that makes the grid unusable. DevExpress solves this with adaptive layout mode: the grid automatically hides less important columns on smaller screens and adds a detail button so users can still access the hidden data.

This is a must-have feature for any live DevExpress grid that needs to work across devices. Below you can compare the same product data in two grids: one with adaptive mode enabled and one without. Resize your browser window to see the difference.

Adaptive layout requires these settings:

1. AdaptivityMode = GridViewAdaptivityMode.HideDataCells
   Automatically hides columns that don't fit the width.

2. AdaptiveColumnPosition = Last (or First)
   Controls which columns are hidden first.

3. AdaptiveDetailColumnCount = 1
   Adds a detail button column for accessing hidden data.

4. AllowOnlyOneAdaptiveDetailExpanded = true
   Only one row's adaptive detail can be open at a time.

The grid handles everything automatically based on
available width. No media queries or custom CSS needed.
@Html.DevExpress().GridView(settings => {
    settings.Name = "gvAdaptive";
    settings.KeyFieldName = "ID";
    settings.Width = Unit.Percentage(100);

    // Enable adaptive layout
    settings.SettingsAdaptivity.AdaptivityMode =
        GridViewAdaptivityMode.HideDataCells;
    settings.SettingsAdaptivity.AdaptiveColumnPosition =
        GridViewAdaptiveColumnPosition.Right;
    settings.SettingsAdaptivity.AdaptiveDetailColumnCount = 1;
    settings.SettingsAdaptivity
        .AllowOnlyOneAdaptiveDetailExpanded = true;

    settings.Columns.Add("Name");
    settings.Columns.Add("Category");
    settings.Columns.Add("Price")
        .PropertiesEdit.DisplayFormatString = "c";
    settings.Columns.Add("Stock");
    settings.Columns.Add("IsActive");
    settings.Columns.Add("CreatedDate")
        .PropertiesEdit.DisplayFormatString = "d";

}).Bind(Model).GetHtml()
// Standard grid without adaptive layout:
// Same columns, same data, but NO adaptive settings.
// On narrow screens, this grid creates a horizontal
// scrollbar instead of hiding columns.

@Html.DevExpress().GridView(settings => {
    settings.Name = "gvNonAdaptive";
    settings.KeyFieldName = "ID";
    settings.Width = Unit.Percentage(100);

    // No adaptive settings — columns never hide
    settings.Columns.Add("Name");
    settings.Columns.Add("Category");
    settings.Columns.Add("Price")
        .PropertiesEdit.DisplayFormatString = "c";
    settings.Columns.Add("Stock");
    settings.Columns.Add("IsActive");
    settings.Columns.Add("CreatedDate")
        .PropertiesEdit.DisplayFormatString = "d";

}).Bind(Model).GetHtml()

Adaptive Grid (Responsive)

This grid uses AdaptivityMode.HideDataCells. Resize your browser to a narrow width and columns will automatically hide, replaced by a detail button.

Product Name 
Category 
Price 
In Stock 
Active 
Created 
xv
 
Laptop Pro 15"Electronics$1,299.99453/5/2026...X
Wireless MouseAccessories$29.992304/4/2026...X
USB-C HubAccessories$59.991204/19/2026...X
Mechanical KeyboardElectronics$149.99785/4/2026...X
Monitor 27" 4KElectronics$499.99325/14/2026...X
Webcam HDAccessories$79.99955/19/2026...X
Desk Chair ErgonomicFurniture$349.99185/24/2026...X
Standing DeskFurniture$599.99125/29/2026...X

Standard Grid (Non-Adaptive)

Same data, same columns, but no adaptive layout. On narrow screens, this grid creates a horizontal scrollbar instead.

Product Name 
Category 
Price 
In Stock 
Active 
Created 
xv
Laptop Pro 15"Electronics$1,299.99453/5/2026
Wireless MouseAccessories$29.992304/4/2026
USB-C HubAccessories$59.991204/19/2026
Mechanical KeyboardElectronics$149.99785/4/2026
Monitor 27" 4KElectronics$499.99325/14/2026
Webcam HDAccessories$79.99955/19/2026
Desk Chair ErgonomicFurniture$349.99185/24/2026
Standing DeskFurniture$599.99125/29/2026
Try it: Resize your browser window to a narrow width (or use your browser's device emulator). Watch how the adaptive grid above hides columns and shows a detail expand button, while the standard grid below simply overflows with a horizontal scrollbar. Click the adaptive detail button to see hidden column data.

Summary: All DevExpress Grid Editing Modes

Throughout this tutorial, we have demonstrated five distinct approaches to data editing in DevExpress GridView:

Editing Mode Best For User Experience See In
Batch Editing Bulk updates, spreadsheet-like editing Click any cell, tab through, save all at once Step 5
Inline Editing Controlled row-by-row updates Edit one row at a time with Update/Cancel Step 7
Edit Form Complex forms with many fields Dedicated form with layout control Step 8
Master-Detail Parent-child data relationships Expand rows to see related child records Step 4
Read-Only Data viewing with sort/filter/export No editing, focus on data analysis Steps 2-3
Adaptive Layout Responsive grids for mobile and tablet Auto-hides columns, detail button for hidden data Step 11

Each mode has its place in production applications. Many real-world systems use multiple modes in the same application—batch editing for bulk imports, inline editing for quick corrections, edit forms for detailed data entry, and master-detail for hierarchical data exploration.


Frequently Asked Questions About DevExpress Grid Demos

This page provides a complete online DevExpress grid demo with 11 live interactive examples you can try directly in your browser. Each demo covers a different feature: sorting, filtering, batch editing, inline editing, edit form mode, master-detail, grouping, summaries, export to Excel/PDF, selection, and adaptive responsive layout. No installation needed — just scroll through and interact with each live DevExpress grid.

Yes! This page contains multiple samples of DevExpress MVC grids with full source code showing the Model, View, and Controller layers. Each sample is a working live grid you can interact with — click cells to edit, expand rows for master-detail, export data to Excel or PDF, and more. The source code for every sample is available behind the "View Source Code" toggle.

Yes. Every grid on this page is a live DevExpress grid running on a real ASP.NET MVC server. You can sort columns, filter rows, search across all fields, edit cells, add new rows, delete rows, export data to Excel/PDF/CSV, and test all features in real time without installing anything.

DevExpress GridView supports four main editing modes:

  • Batch Editing — Spreadsheet-like editing where users modify multiple cells and save all changes at once (demonstrated in Step 5)
  • Inline Editing — Row-by-row editing where clicking Edit transforms a row into editable fields (demonstrated in Step 7)
  • Edit Form Mode — Opens a dedicated form for data entry with full layout control (demonstrated in Step 8)
  • Master-Detail — Expands rows to show related child records in nested grids (demonstrated in Step 4)

Batch editing requires setting SettingsEditing.Mode = GridViewEditingMode.Batch, configuring the BatchUpdateRouteValues, and creating a controller action that accepts MVCxGridViewBatchUpdateValues. See our live batch editing sample in Step 5 above for the complete implementation with working code.

Yes, DevExpress GridView supports powerful data grouping with drag-and-drop column headers, multiple group levels, group-level summaries (count, sum, average, min, max), and total footer summaries. Our live grouping demo in Step 9 shows tasks grouped by Project and Priority with aggregate calculations.

Absolutely. DevExpress provides built-in server-side export methods: GridViewExtension.ExportToXlsx(), ExportToPdf(), ExportToCsv(), ExportToRtf(), and more. These methods respect your column formatting, visibility settings, and sort order. Try the live export buttons in Step 6 to download invoice data in Excel, PDF, or CSV format.

Set the column's ColumnType = MVCxGridViewColumnType.ComboBox (or DateEdit, SpinEdit, CheckBox, ProgressBar) and configure the properties through the column's PropertiesEdit. Our live Edit Form demo in Step 8 shows all these editor types in action with full source code.

The DevExpress adaptive grid automatically hides less important columns on smaller screens and shows a detail button so users can still access hidden data. Enable it with settings.SettingsAdaptivity.AdaptivityMode = GridViewAdaptivityMode.HideDataCells and set AdaptiveColumnPosition to control which columns hide first. See our live adaptive grid comparison in Step 11.

Enable checkbox selection with settings.CommandColumn.ShowSelectCheckbox = true and settings.SettingsBehavior.AllowSelectByRowClick = true. Use GetSelectedKeysOnPage() on the client side to retrieve selected IDs, then POST them to a controller action for server-side processing. See our live selection demo in Step 10.

Need an Expert to Build Your Grid Systems?

With over 10 years of experience in DevExpress development, I can help you build high-performance, secure, and complex grid systems for your business. Whether you are migrating from legacy systems or starting a new project, I provide the end-to-end expertise you need.