Master-Detail with DevExpress Extensions for ASP.NET MVC
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:
- Microsoft Visual Studio 2010 (we are not aware of any reason for non-compatibility with the VS 2008. We had no opportunity to test.)
- 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
- ASP.NET MVC Overview – GridView at
http://documentation.devexpress.com/#AspNet/CustomDocument8998 - How to Start Using DevExpress Extensions in an MVC Web Application at http://www.devexpress.com/Support/Center/p/K18376.aspx
- Master-detail view in MVCxGridView – issue report at
http://www.devexpress.com/Support/Center/p/Q260747.aspx - MVC Templates for DevExpress at
http://devxmvctempates.codeplex.com/ - 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
Post Comment
iq8oSG wonderful points altogether, you simply gained a new reader. What would you recommend in regards to your post that you made some days ago? Any positive?
7smckp Im thankful for the blog.Really looking forward to read more. Awesome.
AxVDUE Thank you, I have just been looking for info about this subject for ages and yours is the best I have discovered so far. But, what about the bottom line? Are you sure about the source?
L0MjKU Thanks for the post.Thanks Again. Fantastic.
XyQLiM Wonderful issues altogether, you simply won a new reader. What would you suggest in regards to your publish that you made a few days ago? Any certain?
l2VrUY This is really interesting, You are a very skilled blogger. I have joined your feed and look forward to seeking more of your magnificent post. Also, I have shared your web site in my social networks!
oDosZq This very blog is without a doubt cool and also informative. I have discovered many handy things out of this amazing blog. I ad love to visit it over and over again. Thanks!
JUdRlF Im grateful for the blog.Much thanks again. Really Great.
skEofb Thanks a lot for the blog post.Really looking forward to read more. Cool.
require instant cash winstar casino concerts however, given that a property loan can be a long-term
tHBpHn Wow, this piece of writing is pleasant, my sister is analyzing such things, thus I am going to let know her.
D3pkx9 That is a good tip especially to those fresh to the blogosphere. Brief but very accurate information Many thanks for sharing this one. A must read article!
kM7BMI Thank you for another great post. The place else could anybody get
YMaYbX
OPDBEZ Wow!!! Great! I like strawberries! That is the perfect recipe for spring/summer period.
vB4KZC Really enjoyed this article post. Much obliged.
xxUW9j Im thankful for the post.Thanks Again. Fantastic.
lybS6z Thank you for your blog post.Much thanks again. Want more.
3cdGa1 Hi my friend! I wish to say that this post is awesome, nice written and include almost all vital infos. I would like to see more posts like this.
wzmdso This website online can be a walk-by way of for all of the data you needed about this and didn't know who to ask. Glimpse here, and also you'll positively discover it.
vRV4RU Very neat blog.Really looking forward to read more.
tHaz0m Hey, thanks for the blog post.Much thanks again. Keep writing.
L4eHQN I think this is a real great post.Really looking forward to read more. Fantastic.
uCd1NS Thank you ever so for you post.Much thanks again. Will read on...
XIbk1F I really liked your blog article.Really thank you! Fantastic.
yMoTa3 Im grateful for the article.Thanks Again. Really Great.
xkEBWm Say, you got a nice blog.Really thank you! Really Great.
B0X1xe Wow, great article post.Much thanks again. Keep writing.
vFfgHa Enjoyed every bit of your blog. Great.
25wsnr Thanks for sharing, this is a fantastic article.Really looking forward to read more.
u2RKzi I appreciate you sharing this blog post.Much thanks again. Much obliged.
zVeExa I really liked your blog article.Really looking forward to read more.
Zo3DpI Im obliged for the post.Really thank you! Much obliged.