Master-Detail View

The Grid View control allows you to build master-detail layouts of any complexity and nesting depth by providing a detail row template, which defines the way detail data is presented.

This demo demonstrates how you can use nested grid controls to visualize a simple master-detail relationship between two data models. To achieve this goal, use the following steps.

  1. Create a Master view file and all action methods required for the Master Grid View (each method should return the Master view using the PartialView method). Add a Master Grid View into the Master view and map routes from the view file to the created action methods using the MapRoute method (available through Routes).
  2. Create a Detail view file and all action methods required for the Detail Grid View (each method should return the Detail view via the PartialView method). Add the Detail Grid View into the Detail view and map routes from the Grid View to the created action methods using the MapRoute method.
  3. Enable displaying detail rows for the Master Grid View using the ShowDetailRow method (available through SettingsDetail).
  4. Specify the Master Grid View's detail row template using the DetailRow method (available through Templates). Add the Detail view to the template content. You can achieve this by either calling the @Html.Partial method or wrapping the Detail View in a View Component and invoking the component's action (which returns the Detail view) from the template.
  5. Pass the current row key from the Master Grid View to the Detail view actions. This key should be used by the Detail Grid View and its action methods to filter data by the current row. For the Detail Grid View to display correct data, the current row key should be stored between requests and passed to the server side actions. You can store it in the ViewData dictionary and pass it as a custom route parameter (using the MapRoute method).
Contact Name Company Name City Country
Maria AndersAlfreds FutterkisteBerlinGermany
 
Order ID Order Date Ship Name Unit Price Quantity Total
1070210/13/2015Alfred's Futterkiste$10.006$60.00
109523/16/2016Alfred's Futterkiste$25.0016$400.00
106438/25/2015Alfreds Futterkiste$46.0015$690.00
109523/16/2016Alfred's Futterkiste$46.002$92.00
106438/25/2015Alfreds Futterkiste$18.0021$378.00
Ana TrujilloAna Trujillo Emparedados y heladosMéxico D.F.Mexico
Antonio MorenoAntonio Moreno TaqueríaMéxico D.F.Mexico
Thomas HardyAround the HornLondonUK
Christina BerglundBerglunds snabbköpLuleåSweden
Hanna MoosBlauer See DelikatessenMannheimGermany
Frédérique CiteauxBlondesddsl père et filsStrasbourgFrance
Martín SommerBólido Comidas preparadasMadridSpain
Laurence LebihanBon app'MarseilleFrance
Elizabeth LincolnBottom-Dollar MarketsTsawassenCanada
@model IEnumerable
@using DevExpress.AspNetCore.DemoModels;
@inject NorthwindContext Northwind
@(Html.DevExpress()
    .BootstrapGridView<Customer>("masterGridView")
    .KeyFieldName(k => k.CustomerID)
    .SettingsDetail(settings => settings.ShowDetailRow(true))
    .Columns(columns => {
        columns.Add(c => c.ContactName);
        columns.Add(c => c.CompanyName);
        columns.Add(c => c.City);
        columns.Add(c => c.Country);
    })
    .Templates(templates => templates
        .DetailRow(detailRow => @<text>
            @Html.Partial("MasterDetail/DetailGridView",
                Northwind.GetInvoicesByCustomerId((string)detailRow.KeyValue),
                new ViewDataDictionary(ViewData) { { "CustomerId", detailRow.KeyValue } })
        </text>))
    .Routes(routes => routes
        .MapRoute(r => r.Controller("GridView").Action("MasterDetailView")))
    .OnBeforeRender((grid, e) => {
        if(!grid.IsPartialUpdate)
            grid.DetailRows.ExpandRow(0);
    })
    .SettingsPager(pager => pager.NumericButtonCount(8))
    .CssClassesPager(css => css
        .PageNumber("d-none d-lg-block")
        .Ellipsis("d-none d-lg-block")
        .Summary("d-none d-md-block"))
    .Bind(Model))
@model IEnumerable
@(Html.DevExpress()
    .BootstrapGridView<DevExpress.AspNetCore.DemoModels.Invoice>()
    .Name($"detailGridView{ViewData["CustomerId"]}")
    .SettingsPager(settings => settings.PageSize(5))
    .KeyFieldName(k => k.OrderID, k => k.ProductID)
    .Columns(columns => {
        columns.Add(c => c.OrderID);
        columns.AddDateEditColumn(c => c.OrderDate);
        columns.Add(c => c.ShipName);
        columns.Add(c => c.UnitPrice);
        columns.Add(c => c.Quantity);
        columns.AddTextColumn()
            .FieldName("Total")
            .UnboundType(UnboundColumnType.Decimal)
            .UnboundExpression("Quantity * UnitPrice")
            .PropertiesTextEdit(properties =>
                properties.DisplayFormatString("c"));
    })
    .CssClassesPager(css => css
        .PageNumber("d-none d-lg-block")
        .Ellipsis("d-none d-lg-block")
        .Summary("d-none d-md-block"))
    .Routes(routes => routes
        .MapRoute(r => r.RouteValues(new {
            Controller = "GridView",
            Action = "MasterDetailView_Detail",
            customerId = ViewData["CustomerId"] })))
    .Bind(Model))
using DevExpress.AspNetCore.DemoModels;
using Microsoft.AspNetCore.Mvc;
namespace DevExpress.AspNetCore.Demos {
    public partial class GridViewController : Controller {
        public ActionResult MasterDetailView() {
            return PartialView("MasterDetail/MasterGridView", NorthwindContext.Customers);
        }
        public ActionResult MasterDetailView_Detail(string customerId) {
            ViewData["CustomerId"] = customerId;
            return PartialView("MasterDetail/DetailGridView", NorthwindContext.GetInvoicesByCustomerId(customerId));
        }
    }
}
Screen Size
Color Themes
Demo QR Code