How to select an element by Class instead of ID in ASP.NET?

The thing is quite easy. In your ASPX:

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

In your codebehind:

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

The codebehind will be hooked up automatically to the PreRender event handler in your class. This casts the sender to the control and sets its Visibility dependent on the css class. You just have to adjust the tags and you don't need a lot code traversing your control collection.


I want to respond to one of the first answers - where we are using recursion to go through all the controls. First of all, shouldn't we be recursing on the child items? I didn't look closely at the code and saw that we kept calling the method recursively on "c", not "child." Secondly, I found that none of the items on my web page could be cast to WebControl - only to HtmlGenericControl.

After editing, I had this:

    // 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;
    }

Note that I couldn't use "CssClass" - I had to put my own attribute ('ishidden') to get to this to work.

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

I'm using ASP.NET framework 2.0/3.0/3.5.


Aside from grouping all of the controls in a single container control, there is no easy way to find a group of controls given some property in ASP.NET server-side code.

On the client side, you could use something like jQuery to find these elements and hide them:

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

I would probably do this in response when the page is fully loaded:

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

One downside to hiding elements in Javascript is that if there's enough data it may take a second and cause content to flicker. Another difference is that hiding content client-side does not remove it from the DOM - the content is there just hidden. Hiding controls server-side prevents their content from even being emitted to the HTML.

Doing the same thing in C# is a bit harder - it requires recursively traversing the control tree and looking for elements in the Control collection that match. This is a common enough operation that a utility function is useful. C# iterator syntax (yield return) is helpful in making this clean:

// 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" );

Hiding the controls now is relatively easy:

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