In 2015 V2.5 September update of C1Studio ASP.NET MVC Edition, we added DetailRow feature to FlexGrid, enabling FlexGrid to display hierarchical data inside nested grids. Let's walk through an example that displays Customer-Order data from Northwind database inside FlexGrid.

The Data

The data comes from the Northwind database, and I'm using Entity Framework for the data model. The name of the model is "C1NWindEntities": Customer-Order Model Customer-Order Model

Providing Data

Here the controller returns "Customer" data in the "MasterDetail" action and Order data in the "DetailRowData" action. In the "DetailRowData" action, the requested Order's "CustomerID" is first checked and then related data from Order model is returned.


public partial class FlexGridController : Controller  
{  
private C1NWindEntities db = new C1NWindEntities(); // db is an instance of C1NWindEntities model.  
// GET: //  
public ActionResult MasterDetail()  
{  
return View(db.Customers.Take(10).ToList());  
}  

public ActionResult DetailRowData([C1JsonRequest] CollectionViewRequest requestData)  
{  
string customerID = requestData.ExtraRequestData["CustomerID"].ToString(); //get the current selected Customer.  
return this.C1Json(CollectionViewHelper.Read(requestData, db.Orders.Where(s => s.CustomerID == customerID).ToList()));  
}  
}  

Show Me The Data

Let's start by initialising FlexGrid to display "Customer" data. Below is the code for initialising FlexGrid in razor view. Notice FlexGrid has a property "ShowDetailRow" which has "DetailRowtemplateID" property that takes reference of a template definition. This template would define the Orders FlexGrid.


@using MvcExplorer.Models  
@using C1.Web.Mvc  
@model IEnumerable  

@(Html.C1().FlexGrid()  
.Id("Customer")  
.ShowDetailRow(d => d.DetailRowTemplateId("detailTemplate").DetailVisibilityMode(C1.Web.Mvc.Grid.DetailVisibilityMode.ExpandMulti))  
.AutoGenerateColumns(false)  
.SelectionMode(C1.Web.Mvc.Grid.SelectionMode.Row)  
.IsReadOnly(true)  
.Bind(Model)  
.Columns(columns =>  
{  
columns.Add(column => column.Binding("CustomerID").Width("*"));  
columns.Add(column => column.Binding("CompanyName").Width("2*").Align("Center"));  
columns.Add(column => column.Binding("Country").Width("2*").Align("Center"));  
columns.Add(column => column.Binding("City").Width("2*").Align("Center"));  
})  
)  

The template definition to display Orders data inside FlexGrid is defined in a script template as follows:


//     @(Html.C1().FlexGrid()  
            .Height("200px")  
            .AutoGenerateColumns(false)  
            .IsReadOnly(true)  
            .Bind(bl=>bl.Bind(Url.Action("DetailRowData")).OnClientQueryData("getCustomer"))  
            .Columns(columns =>  
            {  
                columns.Add(column => column.Binding("ShippedDate").Width("*"));  
                columns.Add(column => column.Binding("Freight").Width("*").Align("Center"));  
                columns.Add(column => column.Binding("ShipVia").Width("*").Align("Center"));  
            })  
            .ToTemplate()  
        )  
// ]]>  

Notice that the Order FlexGrid is bound using Ajax which takes data from "DetailRowData" action defined in the controller. Further, the bind property has "OnClientQueryData" defined which takes reference for a javascript method. This "getCustomer" JavaScript function returns "CustomerID" for which the Order data has to be displayed. Below is the definition for "getCustomer" javascript function:


//     function getCustomer(sender, e) {  
        if (e.extraRequestData == null) {  
            e.extraRequestData = {};  
        }  

        grid = wijmo.Control.getControl("#Customer");  
        if (grid) {  
            currentItem = grid.collectionView.currentItem;  
            e.extraRequestData["CustomerID"] = currentItem ? currentItem.CustomerID : "";  
        }  
    }  
// ]]>  

Here is the complete view code:


@using MvcExplorer.Models  
@using C1.Web.Mvc  
@model IEnumerable  

//     function getCustomer(sender, e) {  
        if (e.extraRequestData == null) {  
            e.extraRequestData = {};  
        }  

        grid = wijmo.Control.getControl("#Customer");  
        if (grid) {  
            currentItem = grid.collectionView.currentItem;  
            e.extraRequestData["CustomerID"] = currentItem ? currentItem.CustomerID : "";  
        }  
    }  
// ]]>  
//     @(Html.C1().FlexGrid()  
            .Height("200px")  
            .AutoGenerateColumns(false)  
            .IsReadOnly(true)  
            .Bind(bl=>bl.Bind(Url.Action("DetailRowData")).OnClientQueryData("getCustomer"))  
            .Columns(columns =>  
            {  
                columns.Add(column => column.Binding("ShippedDate").Width("*"));  
                columns.Add(column => column.Binding("Freight").Width("*").Align("Center"));  
                columns.Add(column => column.Binding("ShipVia").Width("*").Align("Center"));  
            })  
            .ToTemplate()  
        )  
// ]]>  

@(Html.C1().FlexGrid()  
.Id("Customer")  
.ShowDetailRow(d => d.DetailRowTemplateId("detailTemplate").DetailVisibilityMode(C1.Web.Mvc.Grid.DetailVisibilityMode.ExpandMulti))  
.AutoGenerateColumns(false)  
.SelectionMode(C1.Web.Mvc.Grid.SelectionMode.Row)  
.IsReadOnly(true)  
.Bind(Model)  
.Columns(columns =>  
{  
columns.Add(column => column.Binding("CustomerID").Width("*"));  
columns.Add(column => column.Binding("CompanyName").Width("2*").Align("Center"));  
columns.Add(column => column.Binding("Country").Width("2*").Align("Center"));  
columns.Add(column => column.Binding("City").Width("2*").Align("Center"));  
})  
)  

ComponentOneStudio ASP.NET MVC Nested FlexGrid In this example I showed how to take advantage of DetailRow feature to display Hierarchical data, but it's possible to display arbitrary content inside the detail section due to the template feature. You could display data inside a list or elements enclosed inside a div element.

  • See similar example in action here.
  • Refer the TagHelper example of this feature here.