views:

750

answers:

5

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

+1  A: 

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.

Kirtan
A: 

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.

Jeremy
+2  A: 

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>
Robin Day
Thanks for the response. This would work, but I feel like it would create more of a maintenance problem than repeating the code as I would need a separate control in a separate file for each page.
brad
i agree, the only other think i can think of for now is looping through the controls and adding them dynamically. that will cause you no end of pain with event handlers though.
Robin Day
I don't think I'm using any event handlers in those placeholders, just static html mostly, so this might work.
brad
+3  A: 

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 :)

Dave
A very good point Dave, I have actually played with this sort of thing in order to accomplish my goals.
brad
+1  A: 

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.

HeavyWave