ContentPlaceHolders: Repeated Content - asp.net

Scenario
I have an application using asp.net Master Pages in which I would like to repeat some content at the top and bottom of a page. Currently i use something like this:
Master Page
<html>
<body>
<asp:ContentPlaceHolder ID="Foo" runat="server">
</asp:ContentPlaceHolder>
<!-- page content -->
<asp:ContentPlaceHolder ID="Bar" runat="server">
</asp:ContentPlaceHolder>
</body>
</html>
Content Page
<asp:Content ID="Top" ContentPlaceHolderID="Foo" runat="server">
<!-- content -->
</asp:Content>
<asp:Content ID="Bottom" ContentPlaceHolderID="Bar" runat="server">
<!-- content repeated -->
</asp:Content>
Maintenance
As you know, repeating things in code is usually not good. It creates maintenance problems. The following is what I would like to do but will obviously not work because of the repeated id attribute:
Master Page
<html>
<body>
<asp:ContentPlaceHolder ID="Foo" runat="server">
</asp:ContentPlaceHolder>
<!-- page content -->
<asp:ContentPlaceHolder ID="Foo" runat="server">
</asp:ContentPlaceHolder>
</body>
</html>
Content Page
<asp:Content ID="Top" ContentPlaceHolderID="Foo" runat="server">
<!-- content (no repetition) -->
</asp:Content>
Possible?
Is there a way to do this using asp.net webforms? The solution does not necessarily have to resemble the above content, it just needs to work the same way.
Notes
I am using asp.net 3.0 in Visual Studio 2008

Hey, if someone still needs a solution for this here is what I did:
Put it in the Code File of your master page
protected override void RenderChildren(HtmlTextWriter writer)
{
Control mainPlaceHolder = FindControl("MainContentPlaceHolder");
Control doublePlaceHolder = FindControl("ContentDoublePlaceHolder");
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
using (HtmlTextWriter tw = new HtmlTextWriter(sw))
{
mainPlaceHolder.RenderControl(tw);
}
LiteralControl lc = new LiteralControl(sb.ToString());
doublePlaceHolder.Controls.Add(lc);
base.RenderChildren(writer);
}
I'm not sure about performance issues here, but it certainly works.

In the case where you just want to repeat a string, this worked for me:
<asp:ContentPlaceHolder ID="TitleContent" runat="server" />
Can be referenced elsewhere as:
<% Dim title As LiteralControl = TitleContent.Controls.Item(0)
Response.Write(title.Text)
%>
No warranty on that being the right course of action though :)

As others have said, depending on the content itself there are shortcuts that can be taken depending on the type of content that will be there.
Assuming however you need the "content" to be fully functioning asp.net code then I would suggest a UserControl for each ContentPage that contains the content itself and then you only need to duplicate one line of code.
Example
Master Page
<html>
<body>
<asp:ContentPlaceHolder ID="Foo" runat="server">
</asp:ContentPlaceHolder>
<!-- page content -->
<asp:ContentPlaceHolder ID="Bar" runat="server">
</asp:ContentPlaceHolder>
</body>
</html>
Content Page
<asp:Content ID="Top" ContentPlaceHolderID="Foo" runat="server">
<uc1:Page1Control id="page1Control1" runat="server" />
</asp:Content>
<asp:Content ID="Bottom" ContentPlaceHolderID="Bar" runat="server">
<uc1:Page1Control id="page1Control2" runat="server" />
</asp:Content>

You can create a COMMON user control for the same and add it to your master page in the top & bottom. You can create a property describing whether the control has loaded at the top or bottom.

Depending on the content you may be able to do this in code. If its just HTML just put it in a variable and assign it to the other. If you have controls, you can loop over the controls collection and create a duplicate control and place it in the other area. In either case the second location would not be a contentplaceholder a div should due.

Related

MVC Child Master page with Razor

I have an old MVC2 project that I gradulately convert to MVC 5, with Razor.
As the razor views with ASP Master Pages is not possible, I decided to duplicate the Site.Master into _Layout.cshtml.
Everything is OK But there is a problem, however.
I have an other Master page, TwoColumnsLayout.Master, a kind of "child" master page, that begins like this:
<%# Master MasterPageFile="~/Views/Shared/Site.Master" Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
<asp:Content ContentPlaceHolderID="MetaContent" runat="server">
<asp:ContentPlaceHolder ID="MetaContent" runat="server" />
</asp:Content>
<asp:Content ContentPlaceHolderID="HeadContent" runat="server">
<asp:ContentPlaceHolder ID="HeadContent" runat="server" />
</asp:Content>
<asp:Content ContentPlaceHolderID="MainContent" runat="server">
<div class="breadcrumbs">
...
How is possible to convert and use this one with the Razor engine?
utilize #{ Layout = ""; } feature.
For Example:
~/Views/Shared/_LayoutMain.cshtml:
<html>
<head>
<link href="..." rel="stylesheet" type="text/css" />
</head>
<body>
<!-- header markup -->
#RenderBody()
<!-- footer markup -->
</body>
</html>
~/Views/Shared/_LayoutChild.cshtml:
#{
Layout = "~/Views/Shared/_LayoutMain.cshtml";
}
<!-- Child Layout content -->
<div>
#RenderBody()
</div>
~/Views/MyPage/_SomeViewPage.cshtml:
#{
Layout = "~/Views/Shared/_LayoutChild.cshtml";
}
<div>
#RenderBody()
</div>
You just need to use nested layout templates instead.
Create another layout _TwoColumnsLayout.cshtml with the following:
#{
Layout = "~/Shared/_Layout.cshtml";
}
//Nested specific markup ...
#RenderBody()
Then in your view specify your new nested template as follows:
#{
Layout = "~/Shared/_TwoColumnsLayout.cshtml.cshtml";
}

Not retrieving UserControl from a placeholder control

I have a datagrid with dropdown template under .ascx page. I load it on placeholder control on my .aspx page by using:
Control c = Page.LoadControl("~/CreateChecklist/GridWithMultiDropdown.ascx");
PlaceHolder1.Controls.Add(c);
Now i am trying to read datagrid template white in under placeholder from .aspx page but its show me the "ctl00$palceholder$drodownlist" not taking as a control.
Please help me how can i retrieve this datagrid data under placeholder.
Discard your server side code, go to aspx page then register your control and then place ur control tag inside placeholder and bang, it will work :)
Solution:
<%# Register Src="~/WebUserControl.ascx" TagName="myControl" TagPrefix="myControl" %>
<html>
<head runat="server">
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:PlaceHolder ID="phControl" runat="server">
<myControl:myControl ID="ctrlControl" runat="server" />
</asp:PlaceHolder>
</div>
</form>
</body>
</html>
Regards
Ali Muhammad

ASP.NET ContentPage with Form Controls

I created a content page that references a master page. In the content page I have a form and some form controls with a submit button. When I hit submit though the parameters are not detected on page load in the content page. On top of that the name of the parameters are all messed up.
What is the correct way of adding form controls to the content page and then using Request.QueryString[ID]?
I just realized that Microsoft throws all kinds of extra crap at you when you use master pages. It is absolutely ridiculous, is there a way for me not to go down this route of using all kinds of silly casting and inefficient overhead:
http://www.asp.net/web-forms/tutorials/master-pages/control-id-naming-in-content-pages-cs
My code (MASTER PAGE):
<%# Master Language="C#" AutoEventWireup="true" ClientIDMode="Static" %>
<!DOCTYPE html>
<html lang="en">
<head runat="server">
<title></title>
<asp:ContentPlaceHolder ID="Head" runat="server"></asp:ContentPlaceHolder>
</head>
<body>
<asp:ContentPlaceHolder runat="server" ID="MainContent" />
</body>
</html>
My code (Content Page):
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server">
<label for="iSiteId">Site Id(s)</label>
<asp:TextBox ID="iSiteId" runat="server"></asp:TextBox>
<label for="iVersion">Version(s)</label>
<asp:TextBox ID="iVersion" runat="server"></asp:TextBox>
</asp:Content>
My Code (Content Page but the Code behind)
_siteId = Request.QueryString["iSiteId"];
_categoryId = Request.QueryString["iCategoryId"];
_version = Request.QueryString["iVersion"];
Try these instead:
siteId = iSiteId.Text;
_categoryId = iCategoryId.Text;
_version = iVersion.Text;

adding css class in content pages

I am working on a page which is using a Master page for some default design,
I need some css class to be added to the conent page, which we add normally in script tag in normal pages,
My question is how to add some css content in a page which is using Master page,
Thanks,
Vishal.
In your master page you can add a content area within the <head> block. We call ours "HeadContent".
Our master page's head block looks like this:
<head>
...
<asp:ContentPlaceHolder ID="HeadContent" runat="server" />
</head>
From your content pages you can then include custom scripts/css etc:
<asp:Content runat="server" ID="Head" ContentPlaceHolderID="HeadContent">
<script type="text/javascript" src="<%= Url.Content("~/scripts/gradebook.js") %>"></script>
<style type="text/css">
#import url('<%= Url.Content("~/styles/gradebook.css") %>');
</style>
</asp:Content>
You could add a ConentPlaceHolder in the head area of your masterpage like this:
<head>
....
<asp:ContentPlaceHolder id="PlaceHolderAdditionalPageHead" runat="server" />
</head>
In your content page you just need a content control:
<asp:Content ID="Content1" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="Server">
// Put your css stuff here
</asp:Content>

How do you access user controls on a masterpage from the asp:content page using the master?

I keep getting these requests for 'make me a tool to do xyz' for a web app we're putting up.
So after the third one, I realized it'd be easier to lump them all together and use a master page.
I've got a user control called MessageCenter I use for error, success, and informational messages, and so I dropped that on the master page.
<%# Master Language="VB" CodeFile="tfMasterPage.master.vb" Inherits="tfMasterPage" %>
<%# Register Src="MessageCenter/msgCenter.ascx" TagName="msgCenter" TagPrefix="uc1" %>
<%# Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>INSERT TITLE HERE</title>
<link href="Stylesheets/EogTool.css" rel="stylesheet" type="text/css" />
<link href="stylesheets/TF_Main_Styles.css" rel="stylesheet" type="text/css" />
<link href="stylesheets/TF_Print_Styles.css" rel="stylesheet" type="text/css" media="print" />
</head>
<body style="background-color: #eeeeee">
<form id="form1" runat="server">
<div class="page">
<div class="headerArea">
<div class="LogoImg">
<img alt="Transparency Florida" src="images/TF_Logo.jpg" /></div>
<div class="SealImg">
<img alt="Shining the Light on Florida's Budget" src="images/TF_Seal.jpg" /></div>
</div>
<div class="content">
<h1>
FIS - EOG Table Maintenance</h1>
</div>
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<div>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<div class="content">
<div>
<uc1:msgCenter ID="MsgCenter1" runat="server" />
</div>
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
...
Normally, when the msgcenter is on a regular aspx page, I call its method and stuff from the codebehind as in this sub:
...
rtn = dal.deleteRow(CInt(e.CommandArgument), currentTab())
If Not IsNumeric(rtn) Then
MsgCenter1.addMessage("An Error occured deletion" & rtn, , , , "E")
Else
MsgCenter1.addMessage("Delete Successful", , , , "S")
End If
bindGrid()
MsgCenter1.Visible = True
End Sub
But when I try to do that from the asp:content thing on the page using the masterpage, it tells me that msgCenter1 is not declared. It's some sort of scope issue.
I've read about using findcontrol like
ctype(master.findcontrol("tbWhatever"), textbox).text = "FOO"
But when I try to cast to my user control, it complains because it once again, isn't declared.
I feel as though I'm just missing one piece of the puzzle, but it's been eluding me since around 4PM yesterday.
Any advice, pointers, or links would be most appreciated.
Thanks.
First add this directive to the content page you want to access the master page
<%# MasterType VirtualPath="~/NameOfMasterPage.master"%>
Second, On the master page setup a public propery that returns the control you want to access
public Label MasterLabel
{
get
{
return lblMaster;
}
private set
{
//do nothing
}
}
Lastly just access the control in the content page like so
Master.MasterLabel.Text = "Hello from the content page!";
I know your question has been answered and this doesn't apply to it, but I noticed you're passing in 1 length characters for your "MessageCenter" control. I would use an Enum instead of a string to make your code a little less brittle. As it stands now you can pass "fart" in as a parameter and it will compile just fine. An Enum will give you some compile time checking and avoid any issues at runtime.
Examples:
Message.Success
Message.Error
Message.Warning
this is what i'd been used.
Master.FindControl("ControlID").Visible = false;

Resources