当内容占位符包含任何代码块时,它报告控件集合为空。
例如:
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是否已填充(也请参阅这个问题),但它是否包含任何<%=块。
有谁知道怎么绕过这件事吗?
发布于 2009-06-09 05:48:41
正如我所承诺的,我说过我会看一看。对不起,我昨晚没上传,白天很长,需要打干草!
因此,我检查了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>一切如预期(我相信).
虽然它并不完美..。我不认为在这种情况下我们能得到更多的优雅。我不知道其他控件集合是如何在这些不同的场景中设置的,所以我只连接到ContentPlaceHolder控件。其他模板化控件可能工作也可能不起作用。
有什么想法?
您可以从这里下载该项目
http://code.google.com/p/robcthegeek/source/browse/#svn/trunk/stackoverflow/964724
发布于 2009-08-11 13:02:47
对于评论来说太多了,下面是我终于开始工作的完整代码(改编自@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,这将发生在任何嵌套的母版页上。
发布于 2009-06-08 13:31:51
控件集合是空的,因为当<%= %>脚本标记存在时,文本控件不会添加到控件树中。但是,服务器控件仍将被添加。所以:
<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有一篇很棒的文章这就解释了这种行为
要使代码像这样工作,ASP.NET需要覆盖任何脚本代码所在的特定容器的呈现。它通过在容器上使用SetRenderMethodDelegate并创建一个自定义呈现方法来实现这一点. ASP.NET没有构建控件树文本控件,而是只在容器的<% %>标记出现时才将服务器控件添加到控件树中。为了处理文字内容和脚本标记,ASP.NET生成一个自定义呈现方法。然后,该方法使用HTML显式地写出任何静态TextWriter内容和任何脚本表达式。任何脚本代码(<% %>)都是作为方法本身的原始代码生成的。
不幸的是,我想不出任何优雅的解决方案来解决这个难题。
https://stackoverflow.com/questions/964724
复制相似问题