Inherited layout in ASP.NET MVC - asp.net-mvc

I have default layout _Layout.cshtml for the most pages. However for some group of pages I would like to have slightly modified default layout. I know I could just copy that file a modified it a bit, but it would mean to duplicate the code and maintain two layout with 99% of same code.
I would like to inherit the layout from the default like this:
LayoutInherited.cshtml:
Layout = "~/Views/Shared/_Layout.cshtml";
ViewBag.BodyContentClassSpecial = "";
#section header{
<style>
#body-content {
width: 90%;
margin: 0 auto;
}
</style>
}
It is possible to do something like this?

Yes, layout inheritance is possible. Essentially, you're just creating a layout that itself utilizes a layout, since layouts are just views, there's no issues with that.
You pretty much do it exactly as you described:
_SubLayout.cshtml
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
#RenderBody()
A few things to keep in mind:
The content of the sub-layout will be placed where you have #RenderBody in your base layout, just as the content of a view would be. Your sub-layout still needs its own #RenderBody to determine where the content of the view that utilizes it should be placed.
Any sections defined as required in your base layout must be implemented in your sub-layout or Razor will raise an exception, just as if your view did not implement the section. For example:
_Layout.cshtml
#RenderSection("Foo", required: true)
_SubLayout.cshtml
#section Foo
{
<p>Foo</p>
}
If your view needs to be able to implement a section (required or not), the sub-layout must define it. For example, in the code above, any view using _SubLayout.cshtml would not be able to define a Foo section, because it would no longer exist. An exception would be raised if you tried. In order to allow that view to define that section you would have to do something like the following:
_SubLayout.cshtml
#section Foo
{
#RenderSection("Foo", required: true)
}
This defines the section for the purpose of the base layout and then allows the section to be defined by any view that uses this sub layout.
There's actually a post on my blog that goes into all this in much greater detail if you need it: http://cpratt.co/how-to-change-the-default-asp-net-mvc-themet/

Related

Use single view with two different layouts in Razor

This might be a weird question, but I have two layout files in my project and I have a single view I'd like to render separately in each layout file (depending on URL).
So the issue I have is when I define the sections in the view. Both layout pages have similarly functioning sections, but they are named different. For example, if I wanted to use layout1 it would be #section main1 and for layout2 it would be #section main2.
The view will render the same content within these sections, so can I dynamically set the section name rather than making two copies of the same content with just the section name changed?
You can easily change the layout page by setting the layout you want to use, but you can't dynamically set the name to my knowledge. If you really can't change the section names of one of them, what you could do is create a nested layout of the one, and in that nested layout define section names that match in the nested one.
Basically you define:
#section a
{
#RenderSection("namethatmatchesotherlayout")
}
And through this you can get something that matches.

When should a page use a layout in MVC?

When should a page use layout or render layout? I'm a little confused when I should create a page which the page using layout.
different between
#{
Layout = null;
}
And
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
_Layout is like a masterpage in ASP.NET webforms. If you want to apply a common theme (menu, styles ..) across many pages then _Layout file is the best place to put into.
You can have one single _Layout file for the entire application or one each for each specific module of the application.
_ViewStart file has the reference to the _Layout page used in the application.
If you use the below code then the respective page resets the layout to null and does not render the layout defined in _ViewStart. Code in _ViewStart file gets executed at the start of each View.
#{
Layout = null;
}
If you want any specific layout in a page overriding the default layout defined int _ViewStart then you can do as below
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_OtherLayout.cshtml";
}
You don't need to explicitly set the Layout in any of the individual view files unless if you want to override the default layout defined in _ViewStart.
Or if you want the _ViewStart to decide which layout page to render based on the controller then you can write something like below in _ViewStart page. The view will have the respective layout themes applied when rendered.
#{
var controller = HttpContext.Current.Request.RequestContext.RouteData.Values["Controller"].ToString();
string layout = "";
if (controller == "ReportController")
{
layout = "~/Views/Shared/_ReportsLayout.cshtml";
}
else
{
layout = "~/Views/Shared/_Layout.cshtml";
}
Layout = layout;
}
Ade,
I answered a similar question a while back:
*From scottgu's blog (ref: http://weblogs.asp.net/scottgu/archive/2010/10/22/asp-net-mvc-3-layouts.aspx):
Starting with the ASP.NET MVC 3 Beta release, you can now add a file called _ViewStart.cshtml (or _ViewStart.vbhtml for VB) underneath the \Views folder of your project:
The _ViewStart file can be used to define common view code that you want to execute at the start of each View’s rendering. For example, we could write code within our _ViewStart.cshtml file to programmatically set the Layout property for each View to be the SiteLayout.cshtml file by default:
Because this code executes at the start of each View, we no longer need to explicitly set the Layout in any of our individual view files (except if we wanted to override the default value above).
Important: Because the _ViewStart.cshtml allows us to write code, we can optionally make our Layout selection logic richer than just a basic property set. For example: we could vary the Layout template that we use depending on what type of device is accessing the site – and have a phone or tablet optimized layout for those devices, and a desktop optimized layout for PCs/Laptops. Or if we were building a CMS system or common shared app that is used across multiple customers we could select different layouts to use depending on the customer (or their role) when accessing the site.
This enables a lot of UI flexibility. It also allows you to more easily write view logic once, and avoid repeating it in multiple places.*
see Where and how is the _ViewStart.cshtml layout file linked? for details
The _Layout is a template/framework/masterpage for all your views. It saves you from adding things like menus, sidebars, the html head or javascript/css includes on each and every new view you create. Use a layout page to take have "wrapping" html that is rendered around your views.

Extend element beyond _Layout container MVC ASP.NET (preferred method?)

I'm doing a little experimenting with MVC / Bootstrap / ASP.NET...
Specifically I'm trying to understand a best practice to allow an element to extend past its container based on a given logic, in this case based on the loaded view. (I've read through the threads on showing elements based on a Role membership as well).
I'm trying to replicating the layout shown here: URL To Sample. It has a bootstrap carousel and I like the placement extending the entire width but only showing on the Index (Home) page. Implementing this outside of the classic MVC structure is trivial.
With MVC we have the shared _Layout.cshtml and the container where views are loaded with ...
<div class="container body-content">
#RenderBody()
</div>
It seems the carousel needs either
be placed on the _Layout page and hidden if the loaded view is not the Index page or
be placed on the Index page and allowed to exceed the width of the container
I've tried what I've been able to find in threads but haven't been able to replicate this layout cleanly. Can someone please give a bit of direction?
You could stretch it with css, or a cleaner solution could be to put it in its own (optional) section:
in _Layout:
#RenderSection("carousel", required: false)
<div class="container body-content">
#RenderBody()
</div>
in your front page/home (index) file:
#section carousel {
// code for carousel
}
As commented by #Alex, if your home page is significantly different from the other pages, you can use a separate layout file. To do this, just set the "Layout" global string like this;
in your front page/home (index) file:
#{
Layout = "~/Views/Shared/_FrontPageLayout.cshtml"; // to use a separate file
Layout = null; // to not use a layout file
}

The following sections have been defined but have not been rendered for the layout page "~/Views/Shared/_Layout.cshtml"

I know there are a few questions that have been answered but I didn't find something specific to my case.
I'm using the mobile capabilities of MVC4. So I created a _layout.mobile.cshtml and the corresponding views.
The error above happens when I go in with a mobile device. As you can see, it is trying to display the regular _layout.cshtml instead of the _layout.mobile.cshtml. So I'm assuming it is also trying to display the view (say Index.mobile.cshtm) which doesn't have the section in question. Basically it is mixing the regular layout with the mobile views.
This doesn't happen all the time. If I recycle the pool it works again for a while and then all of the sudden it goes back to having the error and it will continue until I recycle the pool again.
Has anyone seen this problem before that can shed some light?
Thanks
John
In the _ViewStart.cshtml available under the Views folder, change the Layout value to your custom layout. I think this may help.. (Make sure that you are returning View instead of partial view)
for example
#{
Layout = "~/Views/Shared/_layout.mobile.cshtml";
}
In case if you want to change the layout for a specific page you can explicitly define it at the top of the page as a page directive.
in the index.cshtml there is a section being called defined in the original layout file "_LayoutHome.cshtml" that is not defined in the new bootstrap layout.
specifically: #RenderSection("featured", required: false)
So the solution is to either add this section to the new layout (look for it in the original layout and paste it) or simply delete it from the index.cshtml.
I had also face the same problem I removed
#section featured {
From View
Another way to do this is to use a conditional block in your _ViewStart.cshtml page. For example, you may have two layouts depending on the device regular user. Using pseudo-code for the reading of the device/browser type bit, it would look something like this:
#{
if(userIsMobile)
{
Layout = "~/Views/Shared/_MobileLayout.cshtml";
}
else
{
Layout = "~/Views/Shared/_Layout.cshtml";
}
}
I have used this to display or hide sections or menu items as needed for different classes of user; it should work as well for device-specific layouts.
Joey Morgan

Common layout with different design parts for each controller in ASP MVC 4

I have some base layout with site structure. In this default layout I define header tag, body structure and footer:
<html>
<head>...</head>
<body>
<div id="sidebar">...</div>
<div id="entry">#RenderSection("Entry", true)</div>
<div id="footer">...</div>
</body>
Each action in each controller defines in their view own entry section.
<!-- in View/Index.cshtml -->
#section Entry {
Hello from Index action.
}
<!-- in View/Uploads.cshtml -->
#section Entry {
Hello from Uploads action.
}
<!-- in View/Users.cshtml -->
#section Entry {
Hello from Users action.
}
But I also want define different sidebars for each controller. If I put #RenderSection("SideBar", true) in main layout I must repeat sidebar code for each controllers action. I also can't define sidebar design code in main layout because I want use different sibebars for each controller (but I want use same sidebar for each action in controller).
How can I solve this problem without repeating sidebar design code in each view?
I find solution https://stackoverflow.com/a/5573970 but it will be require duplication base site structure for each controller.
Thanks for answers and sorry for my bad english :(.
Put #RenderSection("SideBar", false)
Then you can define the section for certain controller layouts only.
You might want to define separate layouts for each controller and each view in this controller will use controller layout (where you can put your sidebar) instead of default layout. Controller layouts will use default layout.

Resources