views:

357

answers:

3

When a page that uses a master page doesn't have an asp:Content control for one of the master page's ContentPlaceHolders, the default content is shown instead. I want to use that default content on a page that does have an asp:Content control for that ContentPlaceHolder.

In the page that uses the master page I want to decide in code whether to use the default content or the page-specific content. How can I show the default content from the master page instead of the content from the asp:Content control for the ContentPlaceHolderID?

For instance, say I have a ContentPlaceHolder for a menu. The default content shows a basic menu. The page builds the menu from a query, but if there's no result for the query I want to show the default menu. By default though, the empty asp:Content control will be shown. How do I get the master page's default content instead?

+1  A: 

One way to do it is to clear the controls collection of the placeholder contents in the Page_Load and add your updated menu.

protected void Page_Load(object sender, EventArgs e)
{
    if(needsBetterMenu)
    {
        ContentPlaceHolder holder = (ContentPlaceHolder)Master.FindControl("ContentPlaceHolder1");
        holder.Controls.Clear();
        holder.Controls.Add(betterMenu);
    }
}
Mike J
Should probably do this in Init rather than Page_Load, in order to get event firing on betterMenu.
Bryan
I'll remember this hint. And yes, better add control on Init stage and registrate for lifecycle events if needed.
terR0Q
This is assuming that the page that uses the master page doesn't have an asp:Content control for ContentPlaceHolder1. I'd like to find a way to access the default content even if the asp:Content has been added.
Joseph Anderson
A: 

If your fine with changing the content of the Master Page in the code behind of the child page, you can do the following:

Add a runat="server" to the html control in the master page that you want to edit:

Site.Master

...
<ul id="menu" runat="server">
    <li><a href="#">Link 1</a></li>
    <li><a href="#">Link 2</a></li>
</ul>
...

Then in the code behind of a child page that needs to change the menu content, put the following code:

protected void Page_Load(object sender, EventArgs e)
    {
        HtmlGenericControl c = Master.FindControl("menu") as HtmlGenericControl;

        if (c != null)
        {
            c.Controls.Clear();
            c.Controls.Add(new HtmlGenericControl("li") { InnerHtml = "<a href=\"#\">Link 3</a>" });
        }
    }

or whatever html you want to put in the menu control.

A page without the code will output the following html:

<ul id="ctl00_menu">
    <li><a href="#">Link 1</a></li>
    <li><a href="#">Link 2</a></li>
</ul>

and a page with the code with display the following:

<ul id="ctl00_menu">
    <li><a href="#">Link 3</a></li>
</ul>

Obviously you wouldn't want to use this code as is. This was only a prototype. I would refactor it to allow adding content to any control and throw it into a base page class that all my pages would inherit.

Jason
A: 

The best approach I've come up with is not to use default content in the ContentPlaceHolder. Instead, I added the default content in a PlaceHolder adjacent to the ContentPlaceHolder:

<asp:ContentPlaceHolder ID="Menu" runat="server" /><!-- no default content -->
<asp:PlaceHolder runat=server ID="DefaultContentForMenu" Visible=false
    EnableViewState=false >Default menu content here</asp:PlaceHolder>

Then I added a ForceDefaultContentForMenu property to the master page so that pages that use the master page can specify that the default content should be used even if the page provides its own content.

The master page's Render method shows the default content if the ForceDefaultContentForMenu property is true or the content placeholder is empty:

protected override void Render(HtmlTextWriter writer)
{
    if (ForceDefaultContentForMenu || !Menu.HasControls())
    {
        Menu.Controls.Clear();
        DefaultContentForMenu.Visible = true;
    }
    base.Render(writer);
}

Now pages that use the master page will get the default content by default if they don't add their own content for the Menu content placeholder, but can specify that the default content should be used instead of their own content.

The only drawback I've found with this approach is that when Visual Studio adds the content area to a page the default content isn't copied. For the work I'm doing this is a benefit rather than a drawback, since if I'm adding the content area to a page it's because I don't want the default content.

Joseph Anderson