asp:ContentPlaceHolder和代码块问题

时间:2009-06-08 12:40:25

标签: asp.net asp.net-mvc master-pages

当内容占位符包含任何代码块时,它会报告控件集合为空。

例如:

MasterPage.aspx

<asp:ContentPlaceHolder ID="Content1" runat="server" />
<asp:ContentPlaceHolder ID="Content2" runat="server" />

<div>Content1: <%= Content1.Controls.Count %></div>
<div>Content2: <%= Content2.Controls.Count %></div>

APage.aspx

<asp:Content ContentPlaceHolderID="Content1" runat="server">
    Plain text content.
</asp:Content>

<asp:Content ContentPlaceHolderID="Content2" runat="server">
    <%= "Code block content." %>
</asp:Content>

这将呈现以下内容:

  

纯文本内容。代码块内容。

     

Content1:1

     

Content2:0

为什么母版页的ContentPlaceHolder.Controls集合为空?

我想检查是否已填充ContentPlaceHolder(另请参阅this question),但如果它包含任何<%=块,则不能。

有没有人知道解决这个问题?

3 个答案:

答案 0 :(得分:8)

按照承诺,我说我会看看。对不起,我昨晚从未上传,漫长的一天,需要打干草!

所以,我正在检查ContentPlaceHolder.Controls集合之间的差异。我注意到,当使用代码块时,它会翻转为只读。在任何其他方面,它将只是空或填充。

因此,我决定引入一种扩展方法来为我们检查它:

ContentPlaceHolderExtensions.cs

public static class ContentPlaceHolderExtensions
{
    public static bool ContainsControlsOrCodeBlock(this ContentPlaceHolder placeHolder)
    {
        if (placeHolder.Controls.Count > 0)
             return true;

        return placeHolder.Controls.IsReadOnly;
    }
}

然后在母版页中查看:

的Site.Master

<asp:ContentPlaceHolder ID="Content1" runat="server" />
<asp:ContentPlaceHolder ID="Content2" runat="server" />
<asp:ContentPlaceHolder ID="Content3" runat="server" />

<div>Content1: <%= Content1.Controls.Count %></div>
<div>Content2: <%= Content2.Controls.Count %></div>
<div>Content3: <%= Content3.Controls.Count %></div>

<div>Content1 (Ex. Meth.): <%= Content1.ContainsControlsOrCodeBlock() %></div>
<div>Content2 (Ex. Meth.): <%= Content2.ContainsControlsOrCodeBlock() %></div>
<div>Content3 (Ex. Meth.): <%= Content3.ContainsControlsOrCodeBlock() %></div>

作为概念验证,我随后添加了一个内容页面:

的Index.aspx

<asp:Content ContentPlaceHolderID="Content1" runat="server">
Plain Text Content
</asp:Content>

<asp:Content ContentPlaceHolderID="Content2" runat="server">
<%= "Code block content" %>
</asp:Content>

所有呈现的都是预期的(我相信)..

TBH,虽然它不是完美 ..我认为在这种情况下我们不能得到更多的优雅。我不确定在这些不同的场景中如何设置其他控件集合,因此我只使用了ContentPlaceHolder控件。其他模板化控件可能也可能不同。

思想?

您可以从here下载项目:

http://code.google.com/p/robcthegeek/source/browse/#svn/trunk/stackoverflow/964724

答案 1 :(得分:3)

评论太多了,这是我最终完成的完整代码(改编自@Rob Cooper的答案):

public static bool HasContent( this ContentPlaceHolder placeHolder )
{
    if ( placeHolder.Controls.Count > 0 )
    {
        LiteralControl textBlock;
        ContentPlaceHolder subContent;

        foreach ( var ctrl in placeHolder.Controls )
            if ( (textBlock = ctrl as LiteralControl) != null )
            {   //lit ctrls will hold any blocks of text
                if ( textBlock.Text != null && textBlock.Text.Trim() != "" )
                    return true;
            }
            else if ( (subContent = ctrl as ContentPlaceHolder) != null )
            {   //sub content controls should call this recursively
                if ( subContent.HasContent() )
                    return true;
            }
            else return true;   //any other control counts as content

        //controls found, but all are empty
        return false;
    }

    //if any code blocks are used the render mode will be different and no controls will
    //be in the collection, however it will be read only
    return placeHolder.Controls.IsReadOnly;
}

这包括两个额外的检查 - 首先是空文字控件(如果页面包含<asp:Content标签,它们之间有任何空格,则会出现),然后是任何嵌套母版页将出现的子ContentPlaceHolder。 / p>

答案 2 :(得分:2)

控件集合为空,因为当&lt;%=%&gt;脚本标记存在,文字控件不会添加到控件树中。但是,仍会添加服务器控件。所以:

<asp:Content ID="Content2" ContentPlaceHolderID="Content2" Runat="Server">
     <%= "Code block content." %>
     <asp:GridView runat="server" ID="gvTest" />
</asp:Content>

<div>Content2: <%= Content2.Controls.Count %></div>

将返回

  

内容2:1

Rick Strahl有一篇很棒的文章that explains this behavior

  

为了使代码像这样工作,ASP.NET   需要覆盖的渲染   任何特定的容器   脚本代码托管。它通过这样做   使用SetRenderMethodDelegate   容器和创建自定义   渲染方法......

     

而不是建立控制   树文字控件,仅限ASP.NET   向控件添加服务器控件   树时&lt; %%&gt;标签存在于   容器。处理文字   内容和脚本标记,ASP.NET   生成自定义渲染方法。   然后这个方法明确写出来   任何静态HTML内容和任何脚本   使用HTML TextWriter的表达式。   生成任何脚本代码(&lt; %%&gt;)   作为方法本身的原始代码。

不幸的是,我无法想到这个难题的任何优雅解决方案。