【问题标题】:Issue with asp:ContentPlaceHolder and code blocksasp:ContentPlaceHolder 和代码块的问题
【发布时间】:2009-06-08 12:40:25
【问题描述】:

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

例如:

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>

这将呈现以下内容:

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

内容1:1

内容2:0

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

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

有人知道解决这个问题的方法吗?

【问题讨论】:

  • 感谢您对上一个问题的评论 - 稍后从办公室回家后会查看此内容。这让我很感兴趣! (+1 来自我!)稍后会更新 :)

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


【解决方案1】:

按照承诺,我说我会看看。抱歉,我昨晚没有上传,漫长的一天,需要干活!

所以,我正在检查 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>

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

索引.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 和 acc),这是一种享受。我做了一个调整 - 对仅包含空格的单个 LiteralControl 进行额外检查。
  • 好电话,我正在考虑自己添加 :) 谢谢!
【解决方案2】:

评论太多了,这是我终于开始工作的完整代码(改编自@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;
}

这包括两项额外检查 - 首先是针对空文字控件(如果页面包含 &lt;asp:Content 标记且它们之间有任何空格,则会发生这种情况),然后是对任何嵌套母版页都会发生的 sub-ContentPlaceHolder。

【讨论】:

    【解决方案3】:

    控件集合是空的,因为当存在 脚本标记时,不会将文字控件添加到控件树中。但是,仍然会添加服务器控件。所以:

    <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 将服务器控件添加到控件 当 标记存在时的树 容器。处理文字 内容和脚本标记,ASP.NET 生成自定义渲染方法。 然后此方法显式写出 任何静态 HTML 内容和任何脚本 使用 HTML TextWriter 的表达式。 生成任何脚本代码 () 作为方法本身的原始代码。

    很遗憾,我想不出任何优雅的解决方案来解决这个难题。

    【讨论】:

    • 很好的解释。不过,这对 MVC 内容来说是一个痛苦——我不想将 内容与 混杂在一起,以便母版页可以看到内容面板已被使用。必须有办法解决这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-15
    • 1970-01-01
    • 2017-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多