Monday, February 28, 2011

Dynamic Layout with MVC 3 and Razor

The past weekend has seen me at Sydney’s Webcamp.  It was a great 2 days of looking at some of Microsoft's Web Technologies as well as have a play with them in the labs.  Towards the end of the second day, after doing the labs I wanted to, I had a bit of a play wrote a simple site that changed it’s layout based on the querystring in MVC 3/Razor.  I thought I would share it with you.

First, make sure you have the MVC 3 templates, which you can get from Microsoft here.  These can take some time to install, so be patient.  You can also get it via the Web Platform Installer. (Note: I am working from Visual Studio 2010.  I am not sure of the compatibility of MVC 3 with previous versions of Visual Studio.)

Once that is installed, open Visual Studio, select File –> New –> Project.  Open the Visual C# set of Projects, select Web, and then select the ASP.NET MVC 3 Web Application.  Also, enter a name for the application (I have used MVC3DynamicLayout). Then hit OK.

The Project isn’t created yet.  On the next screen, you have the options around the type / template of MVC 3 Project to create.  For our purposes select the Empty Application and the Razor view engine.  Hit OK and your project will create.

So, we have our MVC 3 Project, now to get something that will execute.  Below is a picture of the file structure that we will use as a reference.

First, we create our initial layout.  Right click on the Shared folder (that is under the Views folder), select Add –> New Item.  Select the MVC 3 Layout Page (Razor) and enter site_1.cshtml as the Name.

This will create a new cshtml file, into which I have added some render sections and a <h1> tag to show that this is layout 1.  Note, the inline css is just to make the point of the exercise easier, not something you should do.

<!DOCTYPE html>

<html>
<head>
<title>@ViewBag.Title</title>
</head>
<body>
<div style="width:700px;">
<div style="border: red solid 1px;"><h1>This is layout one</h1></div>
<div style="border: green solid 1px;">
@RenderSection("Header",false)
</div>
<div>
<div style="width:100px; border: black solid 1px; float: left;">@RenderSection("Menu",false)</div>
<div style="width:596px; border: purple solid 1px; float: right;">@RenderBody()</div>
</div>
<div style="clear: both; border: blue solid 1px;">some footer text</div>
</div>
</body>
</html>

Now we need to add a controller.  So go to Controllers in Solution Explorer, right click and select Add –> Controller, and call it HomeController.  Do not select the check box to add action methods for create, update, delete and details scenarios.



And finally, we need to create the view to show with the correct layout.  In the home controller, right click anywhere in the Index function and select Add View.  Make sure you check the Use a layout or master page and have selected the site_1.cshtml layout that we have created.



Now, lets add the content to the view so that something is displayed.  That is in the code below.

@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/site_1.cshtml";
}

@section Header{
<h3>This is the head</h3>
}

@section Menu{
<ul><li>item 1</li><li>item 2</li></ul>
}

And here is the rendering of the body

Now, if you hit F5 you should get the following webpage.



So, at this stage you should have a working MVC 3 site, with some really cool looking layout and great UI. (OK, I joke… :D) But we are not done yet, that was only half of what we want.  Now for the other half, to be able to change the page layout dynamically.  Now, for our purpose dynamically will be a querystring value.


So, first lets create our second page layout. Right click on the Shared folder in the View folder, then add a new item.  As before, MVC 3 Layout Page (Razor) but this time enter site_2.cshtml as the Name.  Below is the code for site_2.cshtml

<!DOCTYPE html>

<html>
<head>
<title>@ViewBag.Title</title>
</head>
<body>
<div style="width:700px;">
<div style="border: green solid 1px;">
@RenderSection("Header",false)
</div>
<div style="border: red solid 1px;"><h1>This is layout two</h1></div>
<div>
<div style="width:596px; border: purple solid 1px; float: left;">@RenderBody()</div>
<div style="width:100px; border: black solid 1px; float: right;">@RenderSection("Menu",false)</div>
</div>
<div style="clear: both; border: blue solid 1px;">some footer text</div>
</div>
</body>
</html>

Now, we need to update the controller to accept the querystring argument and then, if that argument is a “y”, let the view know that it need to change the view layout.

    public ActionResult Index(string canIChangeTheLayout)
{
ViewBag.canIChangeTheLayout = (canIChangeTheLayout == "y")?"":"y";
ViewBag.Layout = "~/Views/Shared/site_1.cshtml";
if (canIChangeTheLayout == "y") ViewBag.Layout = "~/Views/Shared/site_2.cshtml";
return View();
}

And then need to make 2 changes to the view.  One to alter the layout (from the viewbag rather than hardcoded, and the other to create a link to control the querystring.  The new view code is below:

@{
ViewBag.Title = "Index";
Layout = ViewBag.Layout;
}

@section Header{
<h3>This is the head</h3>
}

@section Menu{
<ul><li>item 1</li><li>item 2</li></ul>
}

And here is the rendering of the body
<br /><br />
Link: @Html.ActionLink("change layout", "index", new { canIChangeTheLayout = ViewBag.canIChangeTheLayout })



And vola! If you click on the link you should alternate between the first layout and the layout below:



Well, I hoped you liked this basic review of the MVC 3 Projects and how to change the layout in code.

2 comments:

  1. The layout can be changed on the filterContext in an attribute

    ReplyDelete
  2. Thank you for this entry, I am new in MVC and this help me a lot :)

    ReplyDelete