views:

163

answers:

7

I have a few scattered <p> elements on the aspx page which I am grouping together using a class like so - <p class="instructions" runat="server">

In my code behind, using C# I want to hide these elements, using something like instructions.Visible = false;

However I realize I can only do this in codebehind if I use ID but this will result in invalid HTML/CSS Selector since you can't have multiple ID's with the same ID name...

Alternatively is there another way to group the controls if not by class?

EDIT: I can't use JavaScript, so the selection must be done in C# codebehind/ASP.NET

+1  A: 

You could create a recursive function to walk the pages control array, checking the the CssClass attribute for each control and set as required.

Adrian
This is essentially what happens on the client when you do getElementsByTagName or use jquery selectors to select by class. Instead of walkign the DOM, you are walking the asp.net control tree.
David
I was going to type a rough code example - but LBushkin published a way better than mine would have been!
Adrian
A: 

<asp:Panel> approach

You could put them all inside an if they are consecutively placed in your form. That way you can easily toggle the .Visible property of the panel to hide chunks of the form.

JavaScript approach

You can use the ClientScriptManager.RegisterStartupScript() to emit JavaScript and then use jQuery to hide by class.

rtpHarry
good solutions, unforutnately I can't use JS and my paragraphs are scattered - which is why I tagged them with classes.
firedrawndagger
+2  A: 

If you include the JQuery core, all you have to do is register this script on your page :

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

It uses the JQuery class selector http://api.jquery.com/class-selector/

Daniel Dyson
I like that solution - my major concern is that I can't use JavaScript as some clients have JavaScript enabled.
firedrawndagger
+5  A: 

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;
}
LBushkin
I like the idea. Make the method an extension method, then you can simply go:Page.FindRecursive(c => (c is WebControl)
Sebastian P.R. Gingter
This looks great and a C# solution is exactly what I'm looking for.
firedrawndagger
Perhaps have another look at my answer. It's less code and imho not so expensive by not needing to traverse the control collections. Of course you'd need to adjust the <p> elements in your aspx as a downside.
Sebastian P.R. Gingter
A: 

You can use JQuery Class Name Selector for this purpose.
Another solution is to keep the same id's and not making the controls server side. in JavaScript use document.getElementById to get the controls, in your case you will get an array which will hold all the controls having same id's. Iterate through these controls and set their display attributes accordingly.

GS_Guy
+1  A: 

The thing is quite easy. In your ASPX:

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

In your codebehind:

protected void Paragraph_PreRender(sender object; 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.

Sebastian P.R. Gingter
A: 

Building on the Sebastian P.R. Gingter solution, Here's what I did, although it still feels a bit of a hack considering that I have to use a MS based WebControl instead of opting out for a simpler, HTML control.

In C#:

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

In aspx:

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