This sample demonstrates how to manually provide data for two GridView extensions that are used in a master-detail relationship. In this implementation, only sorting and paging operations of the grids are handled in the corresponding Action methods.
Note that this sample provides a universal implementation approach. It can be easily adopted and used for every custom data source object if it implements the IQueryable interface.
The common logic of each grid’s custom binding implementation is similar to the implementation demonstrated by the E4394 code sample. The difference is that in this sample, the master grid’s detail row template is defined by using another (detail) GridView extension. Each detail grid instance is provided with information on the corresponding master row’s key field value. This value is passed to a detail grid’s Action methods (as a parameter) and to the grid’s Partial View (as a ViewData object).
using System.Collections.Generic;
using System.Linq;
using DevExpress.Data;
using DevExpress.Data.Filtering;
using DevExpress.Data.Linq;
using DevExpress.Data.Linq.Helpers;
using DevExpress.Web.Mvc;
namespace Example.Models {
public class MasterCustomBindingHandlers {
static IQueryable Model { get { return NorthwindDataProvider.GetCustomers(); } }
public static void GetDataRowCount(GridViewCustomBindingGetDataRowCountArgs e) {
e.DataRowCount = Model.Count();
}
public static void GetData(GridViewCustomBindingGetDataArgs e) {
e.Data = Model
.ApplySorting(e.State.SortedColumns)
.Skip(e.StartDataRowIndex)
.Take(e.DataRowCount);
}
}
public static class GridViewCustomOperationDataHelper {
static ICriteriaToExpressionConverter Converter { get { return new CriteriaToExpressionConverter(); } }
public static IQueryable Select(this IQueryable query, string fieldName) {
return query.MakeSelect(Converter, new OperandProperty(fieldName));
}
public static IQueryable ApplySorting(this IQueryable query, IEnumerable<GridViewColumnState> sortedColumns) {
foreach(GridViewColumnState column in sortedColumns)
query = ApplySorting(query, column.FieldName, column.SortOrder);
return query;
}
public static IQueryable ApplySorting(this IQueryable query, string fieldName, ColumnSortOrder order) {
return query.MakeOrderBy(Converter, new ServerModeOrderDescriptor(new OperandProperty(fieldName), order == ColumnSortOrder.Descending));
}
public static IQueryable ApplyFilter(this IQueryable query, string filterExpression) {
return query.AppendWhere(Converter, CriteriaOperator.Parse(filterExpression));
}
}
}
@Html.Action("MasterGridViewPartial")
@Html.DevExpress().GridView(
settings => {
settings.Name = "detailGrid" + ViewData["CustomerID"];
settings.SettingsDetail.MasterGridName = "masterGrid";
settings.CallbackRouteValues = new { Controller = "Home", Action = "DetailGridViewPartial", CustomerID = ViewData["CustomerID"] };
settings.Width = System.Web.UI.WebControls.Unit.Percentage(100);
settings.KeyFieldName = "OrderID";
settings.Columns.Add("OrderID");
settings.Columns.Add("OrderDate").PropertiesEdit.DisplayFormatString = "d";
settings.Columns.Add("ShipName");
settings.Columns.Add("ProductName");
settings.Columns.Add("Quantity");
settings.Columns.Add("UnitPrice").PropertiesEdit.DisplayFormatString = "c";
settings.CustomBindingRouteValuesCollection.Add(
GridViewOperationType.Sorting,
new { Controller = "Home", Action = "DetailGridViewSortingAction", CustomerID = ViewData["CustomerID"] }
);
settings.CustomBindingRouteValuesCollection.Add(
GridViewOperationType.Paging,
new { Controller = "Home", Action = "DetailGridViewPagingAction", CustomerID = ViewData["CustomerID"] }
);
}).BindToCustomData(Model).GetHtml()
@Html.DevExpress().GridView(
settings => {
settings.Name = "masterGrid";
settings.CallbackRouteValues = new { Controller = "Home", Action = "MasterGridViewPartial" };
settings.Width = System.Web.UI.WebControls.Unit.Percentage(100);
settings.KeyFieldName = "CustomerID";
settings.Columns.Add("ContactName");
settings.Columns.Add("CompanyName");
settings.Columns.Add("City");
settings.Columns.Add("Country");
settings.SettingsDetail.AllowOnlyOneMasterRowExpanded = false;
settings.SettingsDetail.ShowDetailRow = true;
settings.SetDetailRowTemplateContent(c => {
Html.RenderAction("DetailGridViewPartial", new { CustomerID = DataBinder.Eval(c.DataItem, "CustomerID") });
});
settings.CustomBindingRouteValuesCollection.Add(
GridViewOperationType.Sorting,
new { Controller = "Home", Action = "MasterGridViewSortingAction" }
);
settings.CustomBindingRouteValuesCollection.Add(
GridViewOperationType.Paging,
new { Controller = "Home", Action = "MasterGridViewPagingAction" }
);
settings.PreRender = (sender, e) => {
((MVCxGridView)sender).DetailRows.ExpandRow(0);
};
}).BindToCustomData(Model).GetHtml()
using System.Linq;
using System.Web;
namespace Example.Models {
public static class NorthwindDataProvider {
const string NorthwindDataContextKey = "DXNorthwindDataContext";
public static NorthwindDataContext DB {
get {
if (HttpContext.Current.Items[NorthwindDataContextKey] == null)
HttpContext.Current.Items[NorthwindDataContextKey] = new NorthwindDataContext();
return (NorthwindDataContext)HttpContext.Current.Items[NorthwindDataContextKey];
}
}
public static IQueryable<Customer> GetCustomers() {
return DB.Customers;
}
public static IQueryable<Invoice> GetInvoices() {
return DB.Invoices;
}
}
}
using System.Linq;
using DevExpress.Data.Filtering;
using DevExpress.Data.Linq.Helpers;
using DevExpress.Web.Mvc;
namespace Example.Models {
public class DetailCustomBindingHandlers {
static IQueryable Model { get { return NorthwindDataProvider.GetInvoices(); } }
public static void GetDataRowCount(GridViewCustomBindingGetDataRowCountArgs e) {
e.DataRowCount = Model
.ApplyFilter(e.State.FilterExpression)
.Count();
}
public static void GetData(GridViewCustomBindingGetDataArgs e) {
e.Data = Model
.ApplyFilter(e.State.FilterExpression)
.ApplySorting(e.State.SortedColumns)
.Skip(e.StartDataRowIndex)
.Take(e.DataRowCount);
}
}
}
<!DOCTYPE html>
<html>
<head>
<title>@ViewBag.Title</title>
@Html.DevExpress().GetStyleSheets(
new StyleSheet { ExtensionSuite = ExtensionSuite.NavigationAndLayout },
new StyleSheet { ExtensionSuite = ExtensionSuite.Editors },
new StyleSheet { ExtensionSuite = ExtensionSuite.GridView }
)
@Html.DevExpress().GetScripts(
new Script { ExtensionSuite = ExtensionSuite.NavigationAndLayout },
new Script { ExtensionSuite = ExtensionSuite.HtmlEditor },
new Script { ExtensionSuite = ExtensionSuite.GridView }
)
</head>
<body>
@RenderBody()
</body>
</html>
using System.Web.Mvc;
using Example.Models;
using DevExpress.Web.Mvc;
using DevExpress.Data.Filtering;
namespace Example.Controllers {
public class HomeController : Controller {
public ActionResult Index() {
return View();
}
public ActionResult MasterGridViewPartial() {
var viewModel = GridViewExtension.GetViewModel("masterGrid");
if(viewModel == null)
viewModel = CreateMasterGridViewModel();
return MasterGridActionCore(viewModel);
}
public ActionResult MasterGridViewSortingAction(GridViewColumnState column, bool reset) {
var viewModel = GridViewExtension.GetViewModel("masterGrid");
viewModel.SortBy(column, reset);
return MasterGridActionCore(viewModel);
}
public ActionResult MasterGridViewPagingAction(GridViewPagerState pager) {
var viewModel = GridViewExtension.GetViewModel("masterGrid");
viewModel.Pager.Assign(pager);
return MasterGridActionCore(viewModel);
}
public ActionResult MasterGridActionCore(GridViewModel gridViewModel) {
gridViewModel.ProcessCustomBinding(
MasterCustomBindingHandlers.GetDataRowCount,
MasterCustomBindingHandlers.GetData
);
return PartialView("MasterGridViewPartial", gridViewModel);
}
public ActionResult DetailGridViewPartial(string customerID) {
var viewModel = GridViewExtension.GetViewModel("detailGrid" + customerID);
if(viewModel == null)
viewModel = CreateDetailGridViewModel(customerID);
return DetailGridActionCore(viewModel, customerID);
}
public ActionResult DetailGridViewPagingAction(GridViewPagerState pager, string customerID) {
var viewModel = GridViewExtension.GetViewModel("detailGrid" + customerID);
viewModel.Pager.Assign(pager);
return DetailGridActionCore(viewModel, customerID);
}
public ActionResult DetailGridViewSortingAction(GridViewColumnState column, bool reset, string customerID) {
var viewModel = GridViewExtension.GetViewModel("detailGrid" + customerID);
viewModel.SortBy(column, reset);
return DetailGridActionCore(viewModel, customerID);
}
public ActionResult DetailGridActionCore(GridViewModel gridViewModel, string customerID) {
gridViewModel.ProcessCustomBinding(
DetailCustomBindingHandlers.GetDataRowCount,
DetailCustomBindingHandlers.GetData
);
ViewData["CustomerID"] = customerID;
return PartialView("DetailGridViewPartial", gridViewModel);
}
static GridViewModel CreateMasterGridViewModel() {
var viewModel = new GridViewModel();
viewModel.KeyFieldName = "CustomerID";
viewModel.Columns.Add("ContactName");
viewModel.Columns.Add("CompanyName");
viewModel.Columns.Add("City");
viewModel.Columns.Add("Country");
return viewModel;
}
static GridViewModel CreateDetailGridViewModel(string customerID) {
var viewModel = new GridViewModel();
viewModel.KeyFieldName = "OrderID";
viewModel.Columns.Add("OrderID");
viewModel.Columns.Add("OrderDate");
viewModel.Columns.Add("ShipName");
viewModel.Columns.Add("ProductName");
viewModel.Columns.Add("Quantity");
viewModel.Columns.Add("UnitPrice");
viewModel.FilterExpression = (new BinaryOperator("CustomerID", customerID)).ToString();
return viewModel;
}
}
}
<!DOCTYPE html>
<html>
<head>
<title>@ViewBag.Title</title>
@Html.DevExpress().GetStyleSheets(
New StyleSheet With { .ExtensionSuite = ExtensionSuite.NavigationAndLayout }, _
New StyleSheet With { .ExtensionSuite = ExtensionSuite.Editors }, _
New StyleSheet With { .ExtensionSuite = ExtensionSuite.GridView } _
)
@Html.DevExpress().GetScripts(
New Script With { .ExtensionSuite = ExtensionSuite.NavigationAndLayout }, _
New Script With { .ExtensionSuite = ExtensionSuite.HtmlEditor }, _
New Script With { .ExtensionSuite = ExtensionSuite.GridView } _
)
</head>
<body>
@RenderBody()
</body>
</html>
@Html.DevExpress().GridView(Sub(settings)
settings.Name = "masterGrid"
settings.CallbackRouteValues = New With {.Controller = "Home", .Action = "MasterGridViewPartial"}
settings.Width = Unit.Percentage(100)
settings.KeyFieldName = "CustomerID"
settings.Columns.Add("ContactName")
settings.Columns.Add("CompanyName")
settings.Columns.Add("City")
settings.Columns.Add("Country")
settings.SettingsDetail.AllowOnlyOneMasterRowExpanded = False
settings.SettingsDetail.ShowDetailRow = True
settings.SetDetailRowTemplateContent(Sub(c)
Html.RenderAction(
"DetailGridViewPartial",
New With {.CustomerID = DataBinder.Eval(c.DataItem, "CustomerID")})
End Sub)
settings.CustomBindingRouteValuesCollection.Add(
GridViewOperationType.Sorting,
New With {.Controller = "Home", .Action = "MasterGridViewSortingAction"}
)
settings.CustomBindingRouteValuesCollection.Add(
GridViewOperationType.Paging,
New With {.Controller = "Home", .Action = "MasterGridViewPagingAction"}
)
settings.PreRender = _
Sub(sender, e)
Dim grid As MVCxGridView = CType(sender, MVCxGridView)
grid.DetailRows.ExpandRow(0)
End Sub
End Sub).BindToCustomData(Model).GetHtml()
Imports Microsoft.VisualBasic
Imports System.Web.Mvc
Imports Example.Models
Imports DevExpress.Web.Mvc
Imports DevExpress.Data.Filtering
Namespace Example.Controllers
Public Class HomeController
Inherits Controller
Public Function Index() As ActionResult
Return View()
End Function
Public Function MasterGridViewPartial() As ActionResult
Dim viewModel = GridViewExtension.GetViewModel("masterGrid")
If viewModel Is Nothing Then
viewModel = CreateMasterGridViewModel()
End If
Return MasterGridActionCore(viewModel)
End Function
Public Function MasterGridViewSortingAction(ByVal column As GridViewColumnState, ByVal reset As Boolean) As ActionResult
Dim viewModel = GridViewExtension.GetViewModel("masterGrid")
viewModel.SortBy(column, reset)
Return MasterGridActionCore(viewModel)
End Function
Public Function MasterGridViewPagingAction(ByVal pager As GridViewPagerState) As ActionResult
Dim viewModel = GridViewExtension.GetViewModel("masterGrid")
viewModel.Pager.Assign(pager)
Return MasterGridActionCore(viewModel)
End Function
Public Function MasterGridActionCore(ByVal gridViewModel As GridViewModel) As ActionResult
gridViewModel.ProcessCustomBinding(AddressOf MasterCustomBindingHandlers.GetDataRowCount, AddressOf MasterCustomBindingHandlers.GetData)
Return PartialView("MasterGridViewPartial", gridViewModel)
End Function
Public Function DetailGridViewPartial(ByVal customerID As String) As ActionResult
Dim viewModel = GridViewExtension.GetViewModel("detailGrid" & customerID)
If viewModel Is Nothing Then
viewModel = CreateDetailGridViewModel(customerID)
End If
Return DetailGridActionCore(viewModel, customerID)
End Function
Public Function DetailGridViewPagingAction(ByVal pager As GridViewPagerState, ByVal customerID As String) As ActionResult
Dim viewModel = GridViewExtension.GetViewModel("detailGrid" & customerID)
viewModel.Pager.Assign(pager)
Return DetailGridActionCore(viewModel, customerID)
End Function
Public Function DetailGridViewSortingAction(ByVal column As GridViewColumnState, ByVal reset As Boolean, ByVal customerID As String) As ActionResult
Dim viewModel = GridViewExtension.GetViewModel("detailGrid" & customerID)
viewModel.SortBy(column, reset)
Return DetailGridActionCore(viewModel, customerID)
End Function
Public Function DetailGridActionCore(ByVal gridViewModel As GridViewModel, ByVal customerID As String) As ActionResult
gridViewModel.ProcessCustomBinding(AddressOf DetailCustomBindingHandlers.GetDataRowCount, AddressOf DetailCustomBindingHandlers.GetData)
ViewData("CustomerID") = customerID
Return PartialView("DetailGridViewPartial", gridViewModel)
End Function
Private Shared Function CreateMasterGridViewModel() As GridViewModel
Dim viewModel = New GridViewModel()
viewModel.KeyFieldName = "CustomerID"
viewModel.Columns.Add("ContactName")
viewModel.Columns.Add("CompanyName")
viewModel.Columns.Add("City")
viewModel.Columns.Add("Country")
Return viewModel
End Function
Private Shared Function CreateDetailGridViewModel(ByVal customerID As String) As GridViewModel
Dim viewModel = New GridViewModel()
viewModel.KeyFieldName = "OrderID"
viewModel.Columns.Add("OrderID")
viewModel.Columns.Add("OrderDate")
viewModel.Columns.Add("ShipName")
viewModel.Columns.Add("ProductName")
viewModel.Columns.Add("Quantity")
viewModel.Columns.Add("UnitPrice")
viewModel.FilterExpression = (New BinaryOperator("CustomerID", customerID)).ToString()
Return viewModel
End Function
End Class
End Namespace
Imports Microsoft.VisualBasic
Imports System.Linq
Imports DevExpress.Data.Filtering
Imports DevExpress.Data.Linq.Helpers
Imports DevExpress.Web.Mvc
Namespace Example.Models
Public Class DetailCustomBindingHandlers
Private Shared ReadOnly Property Model() As IQueryable
Get
Return NorthwindDataProvider.GetInvoices()
End Get
End Property
Public Shared Sub GetDataRowCount(ByVal e As GridViewCustomBindingGetDataRowCountArgs)
e.DataRowCount = Model.ApplyFilter(e.State.FilterExpression).Count()
End Sub
Public Shared Sub GetData(ByVal e As GridViewCustomBindingGetDataArgs)
e.Data = Model.ApplyFilter(e.State.FilterExpression).ApplySorting(e.State.SortedColumns).Skip(e.StartDataRowIndex).Take(e.DataRowCount)
End Sub
End Class
End Namespace
Imports Microsoft.VisualBasic
Imports System.Linq
Imports System.Web
Namespace Example.Models
Public NotInheritable Class NorthwindDataProvider
Private Const NorthwindDataContextKey As String = "DXNorthwindDataContext"
Private Sub New()
End Sub
Public Shared ReadOnly Property DB() As NorthwindDataContext
Get
If HttpContext.Current.Items(NorthwindDataContextKey) Is Nothing Then
HttpContext.Current.Items(NorthwindDataContextKey) = New NorthwindDataContext()
End If
Return CType(HttpContext.Current.Items(NorthwindDataContextKey), NorthwindDataContext)
End Get
End Property
Public Shared Function GetCustomers() As IQueryable(Of Customer)
Return DB.Customers
End Function
Public Shared Function GetInvoices() As IQueryable(Of Invoice)
Return DB.Invoices
End Function
End Class
End Namespace
@Html.DevExpress().GridView(Sub(settings)
settings.Name = "detailGrid" & ViewData("CustomerID")
settings.SettingsDetail.MasterGridName = "masterGrid"
settings.CallbackRouteValues = New With {.Controller = "Home", .Action = "DetailGridViewPartial", .CustomerID = ViewData("CustomerID")}
settings.Width = Unit.Percentage(100)
settings.KeyFieldName = "OrderID"
settings.Columns.Add("OrderID")
settings.Columns.Add("OrderDate").PropertiesEdit.DisplayFormatString = "d"
settings.Columns.Add("ShipName")
settings.Columns.Add("ProductName")
settings.Columns.Add("Quantity")
settings.Columns.Add("UnitPrice").PropertiesEdit.DisplayFormatString = "c"
settings.CustomBindingRouteValuesCollection.Add(
GridViewOperationType.Sorting,
New With {.Controller = "Home", .Action = "DetailGridViewSortingAction", .CustomerID = ViewData("CustomerID")}
)
settings.CustomBindingRouteValuesCollection.Add(
GridViewOperationType.Paging,
New With {.Controller = "Home", .Action = "DetailGridViewPagingAction", .CustomerID = ViewData("CustomerID")}
)
End Sub).BindToCustomData(Model).GetHtml()
@Html.Action("MasterGridViewPartial")
Imports Microsoft.VisualBasic
Imports System.Collections.Generic
Imports System.Linq
Imports DevExpress.Data
Imports DevExpress.Data.Filtering
Imports DevExpress.Data.Linq
Imports DevExpress.Data.Linq.Helpers
Imports DevExpress.Web.Mvc
Namespace Example.Models
Public Class MasterCustomBindingHandlers
Private Shared ReadOnly Property Model() As IQueryable
Get
Return NorthwindDataProvider.GetCustomers()
End Get
End Property
Public Shared Sub GetDataRowCount(ByVal e As GridViewCustomBindingGetDataRowCountArgs)
e.DataRowCount = Model.Count()
End Sub
Public Shared Sub GetData(ByVal e As GridViewCustomBindingGetDataArgs)
e.Data = Model.ApplySorting(e.State.SortedColumns).Skip(e.StartDataRowIndex).Take(e.DataRowCount)
End Sub
End Class
Public Module GridViewCustomOperationDataHelper
Sub New()
End Sub
Private ReadOnly Property Converter() As ICriteriaToExpressionConverter
Get
Return New CriteriaToExpressionConverter()
End Get
End Property
<System.Runtime.CompilerServices.Extension()> _
Public Function [Select](ByVal query As IQueryable, ByVal fieldName As String) As IQueryable
Return query.MakeSelect(Converter, New OperandProperty(fieldName))
End Function
<System.Runtime.CompilerServices.Extension()> _
Public Function ApplySorting(ByVal query As IQueryable, ByVal sortedColumns As IEnumerable(Of GridViewColumnState)) As IQueryable
For Each column As GridViewColumnState In sortedColumns
query = ApplySorting(query, column.FieldName, column.SortOrder)
Next column
Return query
End Function
<System.Runtime.CompilerServices.Extension()> _
Public Function ApplySorting(ByVal query As IQueryable, ByVal fieldName As String, ByVal order As ColumnSortOrder) As IQueryable
Return query.MakeOrderBy(Converter, New ServerModeOrderDescriptor(New OperandProperty(fieldName), order = ColumnSortOrder.Descending))
End Function
<System.Runtime.CompilerServices.Extension()> _
Public Function ApplyFilter(ByVal query As IQueryable, ByVal filterExpression As String) As IQueryable
Return query.AppendWhere(Converter, CriteriaOperator.Parse(filterExpression))
End Function
End Module
End Namespace