当内容占位符包含任何代码块时,它会报告控件集合为空。
例如:
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),但如果它包含任何<%=
块,则不能。
有没有人知道解决这个问题?
答案 0 :(得分:8)
按照承诺,我说我会看看。对不起,我昨晚从未上传,漫长的一天,需要打干草!
所以,我正在检查ContentPlaceHolder.Controls
集合之间的差异。我注意到,当使用代码块时,它会翻转为只读。在任何其他方面,它将只是空或填充。
public static class ContentPlaceHolderExtensions
{
public static bool ContainsControlsOrCodeBlock(this ContentPlaceHolder placeHolder)
{
if (placeHolder.Controls.Count > 0)
return true;
return placeHolder.Controls.IsReadOnly;
}
}
然后在母版页中查看:
<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>
作为概念验证,我随后添加了一个内容页面:
<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;) 作为方法本身的原始代码。
不幸的是,我无法想到这个难题的任何优雅解决方案。