Question

I've been searching the web and not finding any answers (there were a couple close questions on stack overflow but they didn't seem to get answered or be identical), so I thought I'd pose one of my own. It revolves around nested master pages and a content page accessing the Content PlaceHolder of the grandparent master even if it is not re-exposed in the parent nested master. I'm wondering if this is not possible.

Core Site.Master

<html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">

        <title>
                <asp:ContentPlaceHolder ID="TitleContent" runat="server">
                    <%= Html.GlobalModel().PageTitle %>
                </asp:ContentPlaceHolder>
            </title>

            <asp:ContentPlaceHolder ID="HeadContent" runat="server">
            <link rel="shortcut icon" 
                href="<%= ViewContext.ClientContent( "Content/Tiki.ico" ) %>" 
                type="image/x-icon"/>
        </asp:ContentPlaceHolder>
    </head>
    <body>
        <asp:ContentPlaceHolder ID="SiteContent" runat="server"/>
    </body>
</html>

Nested Site.Master (notice how TitleContent and HeadContent weren't customized, so the 'default' content from Core Site.Master should take affect)

<%@ Master Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
    Inherits="System.Web.Mvc.ViewMasterPage" %>

<asp:Content ContentPlaceHolderID="SiteContent" runat="server">
    <asp:ContentPlaceHolder ID="SiteContent" runat="server">

        <h1>Nested Header</h1>
        <asp:ContentPlaceHolder ID="NestedContent" runat="server"/>

    </asp:ContentPlaceHolder>
</asp:ContentPlaceHolder>

ContentView.aspx (referencing Nested Site.Master, the attempted TitleContent replacement will not work.)

<%@ Page Language="C#" MasterPageFile="Site.Master" %>

<asp:Content ContentPlaceHolderID="NestedContent" runat="server">
    <p>Nested content.  This will work.</p>
</asp:Content>

<asp:Content ContentPlaceHolderID="TitleContent" runat="server">
    Nested Title.  This will **not** work.
</asp:Content>
Was it helpful?

Solution

ContentPlaceHolderIDs can only reference their immediate parent when listed declaratively.

The easiest fix, though not the most elegant, would be to copy the ContentPlaceHolders to Nested Site.Master with the same default code. Requires some code duplication, but gets the job done.

<%@ Master Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
    Inherits="System.Web.Mvc.ViewMasterPage" %>

<asp:Content ContentPlaceHolderID="TitleContent" runat="server">
    <asp:ContentPlaceHolder ID="NestedTitleContent" runat="server">
        <%= Html.GlobalModel().PageTitle %>
    </asp:ContentPlaceHolder>
</asp:ContentPlaceHolder>

<asp:Content ContentPlaceHolderID="SiteContent" runat="server">
    <asp:ContentPlaceHolder ID="SiteContent" runat="server">
        <h1>Nested Header</h1>
        <asp:ContentPlaceHolder ID="NestedContent" runat="server"/>
    </asp:ContentPlaceHolder>
</asp:ContentPlaceHolder>

If you don't want to do that, you could replace the placeholders with custom controls that know what to show when.

Or if you need to keep it this way, you could run a bunch of code to force early rendering to an in-memory string/buffer and replace child controls with it — but that would be a ton of hassle, and it's doubtful if it would be worth the effort.

But any of those solutions depends on your situation. If you provided more context, we could provide more specific advise.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top