ASP MVC 3 use different Layouts in different views - asp.net-mvc

I have an ASP MVC application which needs multiple different layouts. In ASP.NET Web Apps I would have just made separate master pages. How do I do this in ASP MVC 3?
So far I have made a separate Layout.cshtml file for each layout I need.
I tried setting the layout in the view but it is getting blown away from the ViewStart.cshtml which is setting it back to the default layout for the site.
Also, I can't seem to get intellisense working with Razor so I haven't been able to explore much of what I can do in the ViewStart, if I can conditionally set the Layout, or what.
Thoughts?

You could set the layout dynamically in your controller action:
public ActionResult Index()
{
var viewModel = ...
return View("Index", "_SomeSpecialLayout", viewModel);
}

You can manually set the layout for a view by writing #{ Layout = "~/.../Something.cshtml"; } on top.
EDIT: You can pass the layout name as a parameter to the View() method in the controller.

This method is the simplest way for beginners to control layout rendering in your ASP.NET MVC application. We can identify the controller and render the layouts as per controller. To do this we write our code in the _ViewStart file in the root directory of the Views folder. The following is an example of how it can be done.
#{
var controller = HttpContext.Current.Request.RequestContext.RouteData.Values["Controller"].ToString();
string cLayout = "~/Views/Shared/_Layout.cshtml";
if (controller == "Webmaster") {
cLayout = "~/Views/Shared/_WebmasterLayout.cshtml";
}
Layout = cLayout;
}

Related

ASP.NET MVC ActionMailer Email Layout?

With ActionMailer, can a layout page be specified for a view to use? If so, should the layout page be a regular cshtml view or does it also need to be html.cshtml / txt.cshtml?
I've commented out some of the lines where I tried specifying the layout, but it did not work.
MailController
public EmailResult Welcome(User userInfo)
{
/*Create ViewModel*/
To = "user#email.com";
From = "test#email.com";
Subject = "Welcome!";
/*return Email("Welcome",welcomeVM,"EmailLayout",true);*/
return Email("Welcome", welcomeVM);
}
Welcome.html.cshtml
#model WelcomeVM
{
//Layout = "EmailLayout"
Layout = null;
}
#*Email Contents Here*#
I'm used to the MvcMailer lib. However, try specifying a Layout page this way:
#{
Layout = "~/Views/Shared/MyLayout.cshtml";
}
Just make sure the layout page exists in the path specified.
From ActionMailer's doc page in step 2, it mentions that it's possible to use Layouts:
Now we need to create a View for this email. The view can use any
ViewEngine you like, and it will even work with master pages (or
layouts in Razor). The views live in the same place your normal views
do.

ASP.NET MVC migrating master page - Problems with web control logic

I'm trying to migrate an existing ASP.NET Webforms 3.5 application into an ASP.NET MVC 3 application. That means, I attempt to convert existing .aspx pages with webcontrols and codebehind recpectively with controller logic and razor views.
At the moment I'm focusing on the master page (to get an analogue layout.cshtml for all other razor views).
For example I've replaced controls like asp:Menu, asp:LoginView with partial views and #Html.Action to invoke the controller action, run some code that has been in the codebehind of that masterpage before and return that partial view.
But now I'm getting lost with many web controls of the masterpage that have been set in/visible, depending on the code behind. For example there are two asp:panels in the master page that have been switched in/visible depending on the visited page.
The problem is that in razor views I don't have web controls and in controllers I cannot set attributes/properties (like private int counter;).
Thus I don't know how to carry on...
I hope you have got some ideas or experience with this situation.
Please ask if any information is missing.
You can either set properties of the Model or ViewData in the Controller and then use these in the Razor view with #if
e.g.
On the controller:
public ActionResult Index()
{
ViewBag.Foo = IsThisFoo();
View();
}
In the View:
#if (ViewBag.Foo) {
<p>This is foo</p>
}
else
{
<p>This is bar</p>
}
nb: best practice would be to do it as part of a strongly typed Model for the view

How to use other Layout for page the _Layout.vbhtml in .net mvc 3 view

I want to use a different layout for all the Views in one folder. It's all my Panel views controlled by PanelController.vb
Function LogIn() As ActionResult
Return View()
End Function
Currently all the views in my project utilize _Layout.vbhtml for the layout etc.
How can I make these specific pages utilize e.g. _PanelLayout.vbhtml instead of the default?
See below of what files I am talking about:
I am using Visual Studio 2010, .NET MVC 3, Pages are Razor or something like that.
You can define the view's layout file at the top of the view -
#{
ViewBag.Title = "Index"
Layout = "~/Views/Shared/_PanelLayout.vbhtml"
}
The question specifically calls for vbhtml (or vb.net) page. The accepted answer is for cshtml (C#) razor page. The correct answer for vb.net is:
#CODE
Layout ="~/Views/Shared/_PanelLayout.vbhtml"
End Code

Why does MVC look for .aspx and .ascx for both full and partial views?

I've just been bitten by a problem where I have a view (FindUser.aspx) trying to render a partial view (FindUser.ascx). The default search paths for views look for a file named after the view in a variety of folders. Rather surprisingly, for views, it looks for a file with the extensions of .aspx or .ascx. And the partial views use the same list.
Because I've got the two files named the same, the view resolution repeatedly finds the page first, and falls into an endless loop.
I know I can fix this either by calling the view and the partial view different names, or by changing my search locations to be .aspx only for views and .ascx only for partial views.
My question is why does MVC default to looking at both extensions? It seems to make more sense that a view == a page == .aspx and a partial view == a control == .ascx. So why muddy the waters?
Because partial or not, a view is still a view. Having FindUser.aspx and FindUser.ascx is the same as having two regular views with the same name.
I think that the way to avoid the problem you're having is to use different view names. You probably shouldn't have two views whose file name differs only in extension. However, if you really want a strict Page = View, Control = Partial mapping, just create your own ViewEngine by inheriting from WebFormViewEngine and change the view location formats:
public class MyWebFormViewEngine : WebFormViewEngine {
public MyWebFormViewEngine() {
base.ViewLocationFormats
= new string[] {"~/Views/{1}/{0}.aspx", "~/Views/Shared/{0}.aspx" };
base.PartialViewLocationFormats
= new string[] { "~/Views/{1}/{0}.ascx", "~/Views/Shared/{0}.ascx" };
}
}
Then configure it as your View Engine in Application_Start():
// Call this method during Application_Start to setup your view engine
internal static void SetupViewEngines() {
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new MyWebFormViewEngine());
}
For what it's worth I append "Control" to the name of all of my .ascx ViewUserControls. So I would have FindUser.aspx and FindUserControl.ascx. Doesn't solve the problem but it helps you to avoid it by avoiding naming collisions.
You can give MVC the direct path when rendering Views. Say I have a Foo.aspx in my Home folder and a Foo.ascx partial view in Shared. In your action method you can do either:
return View("~/Views/Shared/Foo.ascx"); // or
return View("~/Views/Home/Foo.aspx");
And it will get the proper one you're looking for.
Reason
View == UserControl in ASP.NET MVC.
Fix
Use different names.
Tip
It`s common convention to name usercontrols with underscore prefix.
If you're using Areas, you'll have to add additional LocationFormats in the constructor:
public class ExtensionBasedWebFormViewEngine : WebFormViewEngine
{
public ExtensionBasedWebFormViewEngine()
{
ViewLocationFormats = new[] {"~/Views/{1}/{0}.aspx", "~/Views/Shared/{0}.aspx"};
AreaViewLocationFormats = new[] {"~/Areas/{2}/Views/{1}/{0}.aspx", "~/Areas/{2}/Views/Shared/{0}.aspx"};
PartialViewLocationFormats = new[] {"~/Views/{1}/{0}.ascx", "~/Views/Shared/{0}.ascx"};
AreaPartialViewLocationFormats = new[] { "~/Areas/{2}/Views/{1}/{0}.ascx", "~/Areas/{2}/Views/Shared/{0}.ascx" };
}
}

Disable layout in ASP.NET MVC?

In MonoRail you can just CancelLayout() to not render the layout. In ASP.NET MVC, the only way to affect the layout seems to be to pass the layout name into the View() method like View("myview", "mylayout"); only it seems that passing null or an empty string doesn't do what I'd want.
I ended up creating an empty layout that just rendered the content, but that seems silly.
"Not Render the layout" means exactly that. In the web forms view engine they call layouts "master pages". I want to render just my action's view and not surround it with the master page.
In MVC 3, you can remove the master layout code with:
#{
Layout = "";
}
At the beginning of view add this:
#{
Layout = null;
}
If you want style sheet to remain, you'll need to add reference to it in that view.
To disable this for all pages, edit the _ViewStart.cshtml (in the root, under the 'Views' folder), and ensure that it contains the following:
#{
Layout = null;
}
And to enable the template for any specific view, the following can be added to the .cshtml file for that view, to enable the template:
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
In the Controller action we can set the required layout.
return View("Index", "_LAYOUT_NAME", model);
https://stackoverflow.com/a/5161384/2039603
I see in the right answer it says that "It seems this was impossible in the version of ASP.NET MVC"
Which version are you using? Because I found the solution (I had the same issue) to your problem
So, to Disable Layout in the page, you should use:
#{
Layout = null;
}
And, as suggested here, this could solve your problem:
public ActionResult Index()
{
SampleModel model = new SampleModel();
//Any Logic
return View("Index", "_WebmasterLayout", model);
}
Instead of using a normal view, create a partial view. These can then be used on their own, which acts very much like CancelLayout() - or you can incorporate them into a view that references the Master Page, in which case it will be the full layout. They are also useful if you want to send back a partial HTML chunk in response to an AJAX request.
Not having any luck trying to set the masterPage parameter to "" or null and returning a View (like I didn't)?
Then try this and use PartialView instead:
public ActionResult Article(string id)
{
return PartialView("~/Areas/Store/Views/CustomerService/" + id);
}
I needed to do this to load the contents of a view asynchronously from JS.
It seems this was impossible in the version of ASP.NET MVC I was asking about.
You can create a custom ActionResult that does pretty much anything. The ActionResult controls what is sent back to the client as the response. It would be trivial to create a class that extends ActionResult that does nothing.
One alternative is to actually specify a layout but make that layout empty
"_EmptyLayout.cshtml" that contains nothing or just a comment that says it contains nothing so later someone sees it as intended.

Resources