如何在ASP.NET中按类而不是ID选择元素?

时间:2010-05-04 14:57:18

标签: c# asp.net select css-selectors selection

我在aspx页面上有一些分散的<p>元素,我使用类似的类将它们组合在一起 - <p class="instructions" runat="server">

在我的代码背后,使用C#我想隐藏这些元素,使用类似的东西 instructions.Visible = false;

但是我知道如果我使用ID,我只能在代码隐藏中执行此操作,但这将导致无效的HTML / CSS选择器,因为您不能拥有具有相同ID名称的多个ID ...

或者是否有另一种方法来分组控件,如果不是按类分组?

编辑:我不能使用JavaScript,因此选择必须在C#codebehind / ASP.NET中完成

9 个答案:

答案 0 :(得分:19)

事情很简单。在你的ASPX中:

<p class="instructions" runat="server" OnPreRender="Paragraph_PreRender">

在你的代码隐藏中:

protected void Paragraph_PreRender(object sender; EventArgs e)
{
  Control paragraph = (Control)sender;
  paragraph.Visible = !paragraph.CssClass.Contains("instructions");
}

代码隐藏将自动连接到类中的PreRender事件处理程序。这会将发件人强制转换为控件,并根据css类设置其Visibility。 您只需调整标记,就不需要遍历控件集合的大量代码。

答案 1 :(得分:14)

除了在单个容器控件中对所有控件进行分组之外,在ASP.NET服务器端代码中给定一些属性没有简单的方法来查找一组控件。

在客户端,您可以使用jQuery之类的内容来查找这些元素并隐藏它们:

$(".instructions").hide();

我可能会在页面完全加载时做出响应:

$(document).ready(function() { 
   $(".instructions").hide(); 
});

在Javascript中隐藏元素的一个缺点是,如果有足够的数据,可能需要一秒钟,导致内容闪烁。另一个区别是隐藏内容客户端没有从DOM中删除它 - 内容就是隐藏的。隐藏控件服务器端可防止其内容被发送到HTML。

在C#中做同样的事情有点困难 - 它需要递归遍历控制树并在Control集合中查找匹配的元素。这是一个很常见的操作,实用程序功能很有用。 C# iterator syntax(收益率回报)有助于实现这一目标:

// utility method to recursively find controls matching a predicate
IEnumerable<Control> FindRecursive( Control c, Func<Control,bool> predicate )
{
    if( predicate( c ) )
        yield return c;

    foreach( var child in c.Controls )
    {
        if( predicate( c ) )
            yield return c;
    }

    foreach( var child in c.Controls )
        foreach( var match in FindRecursive( c, predicate ) )
           yield return match;
}

// use the utility method to find matching controls...
FindRecursive( Page, c => (c is WebControl) && 
                          ((WebControl)c).CssClass == "instructions" );

现在隐藏控件相对容易:

foreach( WebControl c in FindRecursive( Page, c => (c is WebControl) && 
                           ((WebControl)c).CssClass == "instructions" ) )
{
    c.Visible = false;
}

答案 2 :(得分:5)

我想回答第一个答案之一 - 我们使用递归来完成所有控件。首先,我们不应该对儿童用品进行递归吗?我没有仔细查看代码,发现我们一直在“c”上递归调用该方法,而不是“child”。其次,我发现我的网页上没有任何项目可以转换为WebControl - 仅限于HtmlGenericControl。

编辑后,我有了这个:

    // utility method to recursively find controls matching a predicate
    IEnumerable<Control> FindRecursive( Control c, Func<Control,bool> predicate )
    {
        if( predicate( c ) )
            yield return c;

        foreach (var child in c.Controls) {
            if (predicate((Control)child)) {
               yield return (Control)child;
            }
        }

        foreach( var child in c.Controls )
            foreach( var match in FindRecursive( (Control)child, predicate ) )
               yield return match;
    }

    foreach (Control c in FindRecursive(Page, c => (c is HtmlGenericControl) &&
         ((HtmlGenericControl)c).Attributes["ishidden"] == "1"))
    {
         c.Visible = false;
    }

请注意,我无法使用“CssClass” - 我必须使用自己的属性('ishidden')来实现此功能。

<div runat="server" ishidden="1"> ... </div>

我正在使用ASP.NET framework 2.0 / 3.0 / 3.5。

答案 3 :(得分:3)

如果您包含JQuery核心,您只需在页面上注册此脚本:

<script>
 $(document).ready(function() {
    $(".instructions").hide();
 });
</script>

它使用JQuery类选择器http://api.jquery.com/class-selector/

答案 4 :(得分:1)

您可以创建一个递归函数来遍历页面控件数组,检查每个控件的CssClass属性并根据需要进行设置。

答案 5 :(得分:1)

<asp:Panel>接近

如果它们连续放在您的表单中,您可以将它们全部放入其中。这样,您可以轻松切换面板的.Visible属性以隐藏表单的块。

JavaScript方法

您可以使用ClientScriptManager.RegisterStartupScript()发出JavaScript,然后使用jQuery按类隐藏。

答案 6 :(得分:1)

在塞巴斯蒂安P.R. Gingter解决方案的基础上,这就是我所做的,尽管考虑到我必须使用基于MS的WebControl而不是选择更简单的HTML控件,它仍然感觉有点黑客。

在C#中:

protected void Paragraph_PreRender(object sender, EventArgs e) 
{
  WebControl paragraph = (WebControl)sender;
  paragraph.Visible = !paragraph.CssClass.Contains("instructions"); 
} 

在aspx中:

 <asp:Label ID="Label1" CssClass="instructions" runat="server" Text="Label" onPreRender="Paragraph_PreRender"></asp:Label>

答案 7 :(得分:1)

我测试了blackcatweb的解决方案。它返回dublicates,所以我修复了它并为WebControls添加了方法。我的代码如下。要按类设置attrName =&#34; class&#34;:

    /// <summary>
    /// Find controls
    /// </summary>
    /// <param name="c">Control</param>
    /// <param name="predicate">Function</param>
    /// <returns>Control's</returns>
    public static IEnumerable<Control> FindRecursive(Control c, Func<Control, bool> predicate)
    {
        if (predicate(c))
        {
            yield return c;
        }

        foreach (Control child in c.Controls)
        {
            foreach (Control founded in FindRecursive(child, predicate))
            {
                yield return founded;
            }
        }
    }

    /// <summary>
    /// Find WebControls by attr
    /// </summary>
    /// <param name="c">Control</param>
    /// <returns>WebControls</returns>
    public static IEnumerable<WebControl> FindWebControlsByAttr(Control baseControl, string attrName, string attrValue)
    {
        foreach (WebControl c in FindRecursive(baseControl, c => (c is WebControl)
            && !string.IsNullOrEmpty(((WebControl)c).Attributes[attrName])
            && ((WebControl)c).Attributes[attrName].Contains(attrValue)))
        {
            yield return c;
        }
    }

    /// <summary>
    /// Find HtmlGenericControls by attr
    /// </summary>
    /// <param name="c">Control</param>
    /// <returns>HtmlGenericControls</returns>
    public static IEnumerable<HtmlGenericControl> FindControlsByAttr(Control baseControl, string attrName, string attrValue)
    {
        foreach (HtmlGenericControl c in FindRecursive(baseControl, c => (c is HtmlGenericControl)
            && !string.IsNullOrEmpty(((HtmlGenericControl)c).Attributes[attrName])
            && ((HtmlGenericControl)c).Attributes[attrName].Contains(attrValue)))
        {
            yield return c;
        }
    }

答案 8 :(得分:-1)

您可以使用JQuery Class Name Selector来实现此目的。
另一个解决方案是保持相同的id而不是控制服务器端。在JavaScript中使用document.getElementById获取控件,在您的情况下,您将获得一个数组,该数组将保存具有相同ID的所有控件。迭代这些控件并相应地设置它们的显示属性。