如何检查ContentPlaceHolder是否为空?

10
如何检查ContentPlaceHolder是否完全为空?
如果ContentPlaceHolder中只有文本,没有标签和控件。
示例Page.Master:
<asp:ContentPlaceHolder runat="server" ID="Content" />

例子 Test.aspx:

<asp:Content runat="server" ContentPlaceHolderID="Content">
    Custom text without controls. Content.Controls.Count is 0 and Content.HasControls is false.
</asp:Content>

我的需求是当占位符为空时,在另一个控件中放置默认内容。

我尝试两次覆盖同一个占位符,但在动态加载时出现错误。


你想要实现什么目标? - Patrick
5个回答

5
您可以实现一个方法,将内容控件渲染成字符串,然后检查该字符串是否包含任何非空格字符:
private bool HasContent(Control ctrl)
{
    var sb = new System.Text.StringBuilder();
    using (var sw = new System.IO.StringWriter(sb)) 
    {
        using(var tw = new HtmlTextWriter(sw))
        {
            ctrl.RenderControl(tw);
        }
    }

    var output = sb.ToString().Trim();

    return !String.IsNullOrEmpty(output);
}

protected void Page_PreRender(object sender, EventArgs e)
{
    var placeholder = Master.FindControl("FeaturedContent");
    var hasContent = HasContent(placeholder);
}

Controls.Count 为 0,但有文本,不为空。 - e-info128
抱歉,模板化的服务器控件无法将.aspx页面中的标记转换为服务器控件。我已经更新了我的答案,并提供了一种可能的方法:在字符串构建器中呈现内容控件,并检查其中是否有任何非空格字符。 - defrost

1

我真的不想运行所有的渲染代码,或者冒着一些控件在被渲染后状态可能会改变的风险。所以我想出了另一种方法。

public static int ChildrenCount(ContentPlaceHolder placeholder)
{
    int total = 0;
    total += placeholder.Controls.OfType<Control>().Where(x => 
        (!(x is ContentPlaceHolder) && !(x is LiteralControl)) ||
        (x is LiteralControl && !string.IsNullOrWhiteSpace(((LiteralControl)x).Text))
    ).Count();
    foreach (var child in placeholder.Controls.OfType<ContentPlaceHolder>())
        total += ChildrenCount(child);
    return total;
}

对我来说,我直接放入内容元素的文本将作为LiteralControl通过OfType返回,并带有相应的内容。不仅如此,我的格式(“\r\n\t”)也将以相同的方式返回。随后的母版页会传递网页中的插槽,因此我还会得到ContentPlaceholders。
现在的任务是获取控件计数,但要排除这些ContentPlaceholders并且排除空格的LiteralControls。使用is运算符非常容易实现这一点。我们只需确保给定的控件既不是这两种类型之一,然后进行计数,或者如果它是一个Literal,则检查其内容是否全部为空格。最后一步是递归地添加相同操作的结果,以便所有子ContentPlaceholders都能正常工作。
最后:
if (ChildrenCount(MyContentPlaceholder) == 0)
    MyContentPlaceholder.Controls.Add(new LiteralControl("My default content!"));

1

这似乎已经发生了变化,因为我在4.5中看到,即使是单个空格,HasControlsContent中仅包含文字时也会返回true。我在我的主页上做了这样的事情:

<asp:Panel id="SidebarPanel" CssClass="Sidebar" runat="server">
    <asp:ContentPlaceHolder id="SidebarContent" runat="server" />
</asp:Panel>

Sub Page_Load(...)
    SidebarPanel.Visible = SidebarContent.HasControls
End Sub

这将呈现侧边栏内容(如果有的话),放置在一个<div class="Sidebar">中,当没有内容时避免在页面上创建一个空的div。

1
你需要首先找到母版页上的ContentPlaceHolder。然后,你可以将第一个控件(始终存在)转换为LiteralControl并使用它的Text属性。所以,从内容页的Page_Load中按预期工作。
protected void Page_Load(object sender, EventArgs e)
{
    var cph = Page.Master.FindControl("Content") as ContentPlaceHolder;
    if (contentPlaceHolder != null)
    {
        string textualContent = ((LiteralControl) cph.Controls[0]).Text;
        if (string.IsNullOrEmpty(textualContent))
        {
            // ...
        }
    }
}

Visual Studio提示:ArgumentOutOfRangeException。我的代码是:string textualContent = ((LiteralControl) CustomHeader.Controls[0]).Text; 如果(string.IsNullOrEmpty(textualContent)) { /* 加载默认标题 */ UserControl head = (UserControl)Page.LoadControl("~/layout/Themes/" + config.themeSelected + "/header.ascx"); CustomHeader.Controls.Add(head); } - e-info128
同样的问题,在字符串文本内容中断:((LiteralControl)cph.Controls[0]).Text; 与相同的错误。当覆盖内容时,会显示以下信息:La colección de controles no puede modificarse porque el control contiene bloques de código (por ej. <% ... %>)。 - e-info128
@WHK:我已经使用你的aspx和master代码进行了测试。它显示Custom text without controls. Content.Controls.Count is 0 and Content.HasControls is false.作为textualContent - Tim Schmelter
是的,我使用Visual Studio 2012,用C#编写ASP,而不使用MVC。 - e-info128
@WHK:我正在使用Visual Studio 2010,但这并不重要。所以我不确定为什么它对我有效而对你无效。如果像PlaceHolderContentPlaceHolder这样的控件不包含任何控件,只有文本,ASP.NET会自动向其中注入一个类型为LiteralControl的“隐形”控件,其Text属性包含文本。这是我在类似问题上的答案:https://dev59.com/km3Xa4cB1Zd3GeqPbzCb#14322105 - Tim Schmelter
顺便问一下,为什么你在上面的代码中使用了ID CustomHeader并显示了Content?另外,你没有使用我的代码来获取母版页(Page.Master.FindControl...)的ContentPlaceHolder引用。你有使用调试器来检查发生了什么吗? - Tim Schmelter

-1

我的看法:

如果它是一个常量内容,你将不得不插入AND,并且根本不会有<Content>

<asp:ContentPlaceHolder>
   <!-- Anything here will be inserted if there's no Content -->
</asp:ContentPlaceHolder>

我不理解你的评论。 - ispiro
为什么要踩这个问题?我认为这个问题足够广泛,可以包括这种情况。 - ispiro
因为这不是问题的目的,所以显然没有内容控制,但如果有的话也可以检测出来。 - e-info128

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接