Click here to Skip to main content
Click here to Skip to main content
Go to top

Master-Detail with DevExpress Extensions for ASP.NET MVC

, 1 Jun 2011
Rate this:
Please Sign up or sign in to vote.
Force DevExpress Extensions for ASP.NET MVC V2010 vol 2 to do Master-Detail

Introduction

The Master-Detail grid is a deep-rooted celebrity of user interfaces. Unfortunately, if you do web applications in ASP.NET MVC 2 using the current version V2010 vol 2 of Developer Express MVC Extensions for ASP.NET MVC (see the references 1 and 2), you are out of luck – at least you were, before you found this little article.

We are sure one day there will be a great solution to this need available from Developer Express. The vendor is aware of the need, they promised the feature in the future: “Unfortunately, the MVCxGridView doesn't support such a feature. I decided to convert this question to a suggestion article and forward it to our developers, so they can examine it. We'll let you know the results” said Vest on 5/28/2010 (see reference 3.)

For the time being, you will have to read the rest of this article and do a little bit more work in your code to have Master-Detail in your DevExpress GridView on MVC web projects.

Author's note (5/31/2011): It just happened. Developer Express announced that part of the new version of Developer Express MVC Extensions for ASP.NET MVC v2011 vol 1 (to be released soon) will be ASP.NET MVC GridView - Master-detail Grid Layout (see reference 5.) That release will certainly save readers from the need of tricks described in this article.

Background

We assume you are familiar with ASP.NET MVC 2 development and also that you have:

  1. Microsoft Visual Studio 2010 (we are not aware of any reason for non-compatibility with the VS 2008. We had no opportunity to test.)
  2. DevExpress trial or licensed version of any package that does include MVC Extensions for ASP.NET MVC. We tested with Developer Express V2010 vol 2.

Solution First, Discussion Later

If you beloved reader are like me, you would appreciate the brevity of the expression. Hence, without much foreplay, I will guide you through the steps you shall do. There will be enough space to discuss the background information later.

Let’s assume you already have an ASP.NET MVC 2 solution with some model and controller. As you stay well advised, to use the DevExpress GridView, you put all the meat into partial page that you render into List action page (let’s call Index to keep things plain):

<%@ Page Title="Cool Master-Detail GridView" Language="C#" 
MasterPageFile="~/Views/Shared/Site.Master" 
Inherits="System.Web.Mvc.ViewPage<IEnumerable<MyParentTable>>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
      Cool Master-Detail GridView
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
     <% Html.RenderPartial("IndexPartial"); %>
</asp:Content>

As you may have noticed, we named the partial view IndexPartial and we are ready to make it. You might have the view page already created or you might be ready to type it. Perhaps you would like to scaffold the view. Well, I hear you; scaffolding is great for plain lists, not available for DevExpress GridView, right? Hear me, go to CodePlex (see reference 4) and download MVC Templates for DevExpress that your well appreciated author posted there for your benefit (Note: Instead of adding the template as a download to this article, we refer you to CodePlex because the template is not the main topic of this article and also CodePlex has great version control features, so you always get your templates fresh.)

Now you have the IndexPartial.ascx page that provides your master grid. Let me assume that you already have the Index and IndexPartial actions in your controller. Your code might look similar to mine:

// GET: /Index/
public ActionResult Index()
{
    IQueryable main = db.GetMasterData();
    return View(main);
}
 
// to support GridView sorting and other peculiarities
public ActionResult IndexPartial()
{
    IQueryable main = db.GetMasterData();
    return View(main);
}

Note: We did notice the code in both actions is exactly the same. We will care about DRY after we are done with this article.

Let’s prepare our detail grid now, starting with the controller action. Let’s assume the master and detail grids will be joined with use of the MasterId – the primary key of the master grid:

[ChildActionOnly]
public ActionResult DetailIndexPartial(int MasterId)
{
    var details = db.GetDetailData(MasterId);
    return View();
}

As our sharp reader certainly noticed, we store the detail page in its own partial view. We can use the same scaffolding template we used for the master grid partial view to create the DetailIndexPartial view too.

We are ready for the magic now!

Do the Magic - Add the Detail Rendering into the IndexPartial.ascx View

1.  <%@ Control Language="C#" 
	Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<MyParentTable>>" %>
2.   
3.  <% 
4.      Html.DevExpress().GridView(
5.          settings =>
6.          {
7.              settings.Name = "gvMainTable";
8.              settings.CallbackRouteValues = 
		new { Controller = "Home", Action = "IndexPartial" };
9.              settings.Width = Unit.Percentage(100);
10.            settings.Columns.Add("MasterId").Caption = 
		"Primary key -- not for user eyes!";
11.            settings.Columns.Add("Name");
12.            settings.Columns.Add("Country");
13.            settings.Columns.Add("Notes");
14.            settings.Columns.Add("Active");
15.            settings.Columns.Add("Edited");
16.            settings.Columns.Add("EditedBy");
17.            settings.Settings.ShowPreview = true;
18.            settings.SetPreviewRowTemplateContent(c =>
19.                 Html.RenderAction("DetailIndexPartial", 
		new { MasterId = DataBinder.Eval(c.DataItem, "MasterId") }));
20.            var commandColumn = settings.Columns.Add("", "");
21.            commandColumn.SetDataItemTemplateContent(c =>
22.            {%>
23.                <%= Html.ActionLink("Edit", "IndexEdit", new 
			{ Id = DataBinder.Eval(c.DataItem, "Id") })%> 
24.                <%= Html.ActionLink("Delete", "IndexDelete", new 
			{ Id = DataBinder.Eval(c.DataItem, "Id") },
25.                        new { onclick = "return confirm
			('Do you really want to delete this record?')" })%>
26.            <%});
27.            commandColumn.Settings.AllowDragDrop = DefaultBoolean.False;
28.            commandColumn.Settings.AllowSort = DefaultBoolean.False;
29.            commandColumn.Width = 70;
30.        })
31.        .Bind(Model)
32.        .Render();
33.%>
34. 
35.    <p>
36.        <%: Html.ActionLink("Create New", "Create") %>
37.    </p>

We added 3 rows: 17 – 19, all the rest came from the scaffolding. We also added the caption to the 1st column (row 10.) to remind you that removing this column (deleting the row 10) might be a good idea.

Run the project, enjoy the look in your Master-Detail page.

I Like It! May I Have More?

More than one level of table nesting is not usually considered the best user interface design practice. However, frequently we are asked to do just that and sometimes it even makes sense. So, can we repeat what we just did? Yes, we can (no pun intended.) We will add one row to the DetailIndexPartial action (notice the row 5):

1.  [ChildActionOnly]
2.  public ActionResult DetailIndexPartial(int MasterId)
3.  {
4.      var details = db.GetDetailData(MasterId);
5.      ViewData["MasterId"] = MasterId;
6.      return View();
7.  }

The avid reader guessed already that we need to create DetailAnotherIndexPartial action in our controller, scaffold the partial view with the third grid and insert its rendering into the IndexPartial view (same as rows 17-19 in the example above, the row 19 will refer to the DetailIndexPartial sending it the DetailId). We need to modify two more rows. We change row 7:

settings.Name = "gvDetailTable" + ViewData["MasterId"];

We change row 36 as well:

<%: Html.ActionLink("Create New", "CreateDetail", 
new { MasterId = ViewData["MasterId"] })%>

Run the project again, enjoy the look at all 3 levels or nesting.

What Did We Do?

GridView preview row is used to insert the nested table into the master. We enable the preview in row 17. We template the contents of the preview in row 18 and finally we insert the detail table using the RenderAction HTML helper method in row 19.

To enable multilevel nesting, we need to add the primary key of the master into the model data of the first detail. We did that at row 5 of the DetailAnotherIndexPartial action. We are using this value to ensure that each nested table has a unique name. This is done in row 7 of the view.

It is rare to have the “Create New” feature in all nesting levels or the master-Detail table. We have it because the ListPartialWithDexGridView template inserted it. Deleting the action link (rows 35-37) is an easy fix. Alternately, to make sure it works, we showed you how to use the ViewData with master table key in the modification of row 36. Sure, you have to support the feature with the CreateDetail action and view.

What We Did Not Do?

Master-Detail grids have those nifty little + and – icons that you can click to show or hide the detail. There are many ways to achieve this behavior. We will do it once as the time permits. Would the kind reader mind sending me an email if you beat me in doing the collapsing of the table detail?

References

  1. ASP.NET MVC Overview – GridView at
    http://documentation.devexpress.com/#AspNet/CustomDocument8998
  2. How to Start Using DevExpress Extensions in an MVC Web Application at http://www.devexpress.com/Support/Center/p/K18376.aspx
  3. Master-detail view in MVCxGridView – issue report at
    http://www.devexpress.com/Support/Center/p/Q260747.aspx
  4. MVC Templates for DevExpress at
    http://devxmvctempates.codeplex.com/
  5. ASP.NET MVC GridView - Master-detail Grid Layout announcement
    Mehul Hary's blog

History

  • 30th January, 2011: Initial post
  • 31st May, 2011: Article updated, see author's note above

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

peter gabris
Technical Lead www.bsp-software.com
United States United States
A neighbor promised to show me the first computer in the city if I detail his motorbike. He let me in and I stayed forever. I learned how to tame the beast. I was 14.
 
A few years later I figured out how to sqeeze hydrological/hydraulic models into 8K memory. The models were used on big rivers including Indus River, Yamuna River, Danube River. The version in Pakistan (that I later converted from FORTRAN to C) is still in use. Over 30 years and still running.
 
6 days took my book Word of Computers (in Slovak language) to completely sell out.
 
Annual LEGO price was awarded to an institute led by me for our work in education. Money went to charity, I still have the tie.
 
Spent years in consulting. Project rescue is a smokejumper's job. I saved a bunch of hoplessly failing projects in areas of procurement, recruitment, check image scanning and ICR, business risk evaluation.
 
15 months took my latest SAAS application to earn million dollars.

Comments and Discussions

 
GeneralMy vote of 1 Pingroupraj98989823-Mar-12 0:29 
GeneralVery nice post Pinmemberjanicko@juno.com4-Feb-11 7:43 
GeneralMy vote of 4 Pinmemberjanicko@juno.com4-Feb-11 7:42 
Generalthanks for sharing PinmemberPranay Rana30-Jan-11 22:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140916.1 | Last Updated 1 Jun 2011
Article Copyright 2011 by peter gabris
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid