ASP.NET MVC nested master pages, inherit content - asp.net-mvc

I have a series of nested master pages, like so:
site.master:
<asp:ContentPlaceHolder ID="SearchFormContent" runat="server">
<%Html.RenderPartial("SearchFormControl"); %>
</asp:ContentPlaceHolder>
in the nested (child) master page, area.master
<asp:Content ContentPlaceHolderID="SearchFormContent" ID="SearchFormContentContainer" runat="server">
<asp:ContentPlaceHolderID="SearchFormContent" runat="server"/>
</asp:ContentPlaceHolder>
I have two separate content pages. One wants to add its own content to SearchFormContent, the other would like to keep the content that was defined in the top-level master page. Of course, since the child master page defines content for the SearchFormContent block so that the child pages can potentially access it, the content defined in the top level master page is obliterated.
Any way to do this?

I can't think of any way other than having the following in your child master page
<asp:Content ContentPlaceHolderID="SearchFormContent" ID="SearchFormContentContainer" runat="server">
<asp:ContentPlaceHolder ID="SearchFormContent" runat="server">
<%Html.RenderPartial("SearchFormControl"); %>
</asp:ContentPlaceHolder>
</asp:ContentPlaceHolder>
Nasty I know, but its the only way I can think of when using master pages.
HTHs,
Charles

Remove all your ContentPlaceHolders and leave the SearchFormControl directly on the site.master. If you never want to override the SearchFormControl then you don't need to define the ControlPlaceHolders

you can put content in the contentPlaceHolder on the masterpage. that will be rendered by default if you don't override the with a content on a child page.

Related

How to structure a websitewhen using boxes

I am designing a page which needs to have boxes (partial views) on both the left and the right side of the main content. The boxes will contain extra information just like on SO. I would like to group the pages, so certain pages will have some boxes, and pages of another group will have other boxes.
I am though in doubt how this is best accomplished in MVC.NET.
I see two options:
1) On every page I include the partial controls I need.
2) Create sub-master pages where I can assign a page to, and which can control which partial views should be shown.
Are there any other ways of doing this, which would be smarter or easier to implement?
Boxes on SO pages are strictly related to content of the page, so I would create one master page with 3 content placeholders (Site.Master):
<asp:ContentPlaceHolder ID="LeftContent" runat="server" />
<asp:ContentPlaceHolder ID="MainContent" runat="server" />
<asp:ContentPlaceHolder ID="RightContent" runat="server" />
If you had some range of functionalities, that have the same boxes, I would create master page for them and place something like (Controller.Master):
<asp:Content runat="server" ContentPlaceHolderID="RightContent">
<% Html.RenderPartial("RelatedTagsInfo", ViewData['RelatedTagsInfoModel']) %>
<% Html.RenderPartial("RelatedQuestionsInfo", ViewData['RelatedQuestionsModel']) %>
<asp:ContentPlaceHolder ID="RightContentSubcontent" runat="server" />
</asp:Content>
Actions using Controller.Master would place additional boxes in RightContentSubcontent.
If boxes are really independent of current page, you can also use RenderAction:
<asp:Content runat="server" ContentPlaceHolderID="RightContent">
<% Html.RenderAction("RelatedTagsInfo", "Question", new { id = Model.Id} ) %>
<% Html.RenderAction("RelatedQuestionsInfo", "Question", new { id = Model.Id} ) %>
<asp:ContentPlaceHolder ID="RightContentSubcontent" runat="server" />
</asp:Content>
RenderAction creates new request to render part of the page. It may be easier to use, but I would use RenderAction for boxes, that do not share any information with the main view (for example if you wanted to display "Clock" box, "Latest downloads" box or "Login" box).
There are many ways to put content into sidebars on pages...
Build different master pages, each containing a different subset of sidebar content. I would use RenderAction for this and not RenderPartial, that way you do not have to worry about having each ActionResult in your MVC Solution be responsible for sending content to these partials.
set up a single RenderAction in the Master page and in the ActionResult for the RenderAction, have it inspect the calling Controller and/or the ActionResult (all contained in the HttpContext). Based on that you can send back content conditionally, and render it in the partial view conditionally.

How to stick a ContentPlaceHolder as the source of a URL in a master page in ASP.NET MVC

I have multiple pages that have this pattern:
<iframe frameborder ="0" src="[someURL]" width="100%" height="900">
</iframe>
I want to factor out everything but the URL into a master page so I tried this:
Master Page:
<iframe frameborder ="0" src=<asp:ContentPlaceHolder ID="Url" runat="server" /> width="100%" height="900">
</iframe>
Child Page:
<asp:Content ID="Content2" ContentPlaceHolderID="Url" runat="server">
"http://myURL"
</asp:Content>
but it doesn't seem to work. I get this error:
Cannot find ContentPlaceHolder 'Url' in the master page
Do I have some syntax error above?
It sounds like you want to re-use a snippet such that the View can dictate what the URL of the iFrame is, and the Master holds the actual iFrame.
Consider this potential solution:
The URL is put into ViewData from the Controller. Convention is that Views are dumb. So you could put this iFrame into your Master:
<iframe frameborder ="0" src="<%=ViewData["yourURL"] %>" width="100%" height="900"></iframe>
This requires that your Controller knows, or can find, the URL for the View that's being requested. You could hard-code this right in your Controller method, or pull it from the web.config.
I don't think that will work very well... Could you pass along a URL into ViewData within the controller instead, and inject that? Or create some component that pulls the correct value from a backend source based on the current URL, or something?
HTH.
There are better ways of getting your source into the element but if you need to stick with the implementation you are using you can do this...
<iframe frameborder ="0" src="<asp:ContentPlaceHolder ID="UrlContent" runat="server" />" width="100%" height="900">
</iframe>
Notice that I have quotes before and after the content placeholder. Then you can just have content that looks like this...
<asp:Content ID="Content3" ContentPlaceHolderID="UrlContent" runat="server">
http://www.stackoverflow.com
</asp:Content>
Intelisense will not like what you are trying to do but it will work.

Anyone Using a Custom ViewMasterPage?

Lately when I've been building my asp.net mvc apps I tend to have a number of items that consistently need to be calculated, formatted and configured in my master pages. Some of these items include:
I like to attach specific classed to the body tag like WordPress does to help my CSS out. I usually attach the name of the action, controller, page template, etc.
I like to work with a custom IIdentity in my master pages. This IIdentity includes the users nice Display Name, UserID, UserName, etc.
etc... depending on the project
The way I've gone about accomplishing this has evolved as well. I started out by sending ViewData along with every action result to populate things in the master page. example->
// in the action
ViewData["BodyClasses"] = "index home default";
ViewData["UserData"] = userData;
return View();
// in the master page
<% UserData userData = (UserData)ViewData["UserData"] %>
...
<body class="<%= (string)ViewData["BodyClasses"] %>">
That was horrible. So I started putting some variables at the top of my master pages and populating them based on the objects we have to work with in the master page. example ->
<%# Master Language="C#" Inherits="System.Web.MVC.ViewMasterPage" %>
<% string controller = ViewContext.RouteData.Values["controller"].ToString().ToLower();
string action = ViewContext.RouteData.Values["action"].ToString().ToLower();
CustomIdentity identity = (CustomIdentity)User.Identity %>
...
<body class="no-js <%= controller + " " + action %>">
That's better but I feel like there has to be an easier solution. I started playing around with creating a custom ViewMasterPage and adding some public properties. Is anyone else doing this with the master page or is there another solution to this that I'm completely missing?
I've used just regular content placeholders for body tag id's and classes.
<body id="<asp:ContentPlaceHolder ID="BodyTagId" runat="server" />">
Then use it in the given page that references the master page:
<asp:Content ContentPlaceHolderID="BodyTagId" runat="server">about-page</asp:Content>

how do i reference the main master in a nested master page scenario in asp.net

i see that this question has been answered:
Are there nested master pages in ASP.NET MVC?
but i have a follow up questions, if i have nested master pages:
site.master
section.master
page
where page has a master of section.master and section.master itself has a master of site.master
can i refer to sections in both section.master and site.master?
or maybe the better questions is that i would like to the do the following and when i try to reference a section in site.master i get "can't find content section.
any suggestions?
i see examples where the page references section.master but i can't find any examples where page references site.master. For example: http://msdn.microsoft.com/en-us/library/x2b3ktt7.aspx
I believe you cannot reference content of parent master page if the page has child master page set.
Instead you can chain the content from child master to parent. Like this:
Top.Master:
<asp:ContentPlaceHolder ID="TopContent" runat="server" />
Child.Master:
<asp:Content ContentPlaceHolderID="TopContent" ID="childContent1" runat="Server">
<asp:ContentPlaceHolder ID="ChildContent" runat="server" />
</asp:Content>
Page.aspx:
<asp:Content ContentPlaceHolderID="ChildContent" ID="pageContent1" runat="Server">
<p>This will go to the Top.Master through Child.Master</p>
</asp:Content>

registering some javascript files from partial views (.ascx)

I have a page composed from multiple partial asp.net mvc views rendered dynamically.
How can I register in the header of the page some javascript files based on what is needed on on each partial view?
I set up a ContentPlaceHolder in the header of the master page for the view. In the view, I include both the header and body content place holders and add my javascript includes in the place holder corresponding to the header. I typically don't add the javascript include to the partial view itself since I (too) want it to appear in the html head element. I just make sure to include all the javascript files that all of my partials will need in the view that includes them. I will, often, include inline script in the partial view itself though you need to be careful with this if the partial can be embedded multiple times.
View Code:
<asp:ContentPlaceHolder ID="headerContent"
ContentPlaceHolderID="Header"
runat="server">
... javascript includes go here...
</asp:ContentPlaceHolder>
<asp:ContentPlaceHolder ID="bodyContent"
ContentPlaceHolderID="Body"
runat="server">
... body content goes here...
<% Html.RenderPartial( "PartialView1", Model, ViewData ); %>
<% Html.RenderPartial( "PartialView2", Model, ViewData ); %>
</asp:ContentPlaceHolder>

Resources