Use ContentPlaceHolder's default content instead of page's content
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. Th开发者_如何学JAVAe 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?
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);
}
}
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.
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.
精彩评论