2

I have a lot of .aspx pages with a lot of controls. These controls are all declared in a similar way:

<input type="text" runat="server" id="txtLatitude" />

Now I have to check who the user is and, if not allowed to make changes, make all these controls readonly. Normally i would do somethink like

txtLatitude.Attributes.Add("readonly", "readonly")

but it would take me forever to do that manually for each control in each page. I was wondering if there is a way to get a List or something of all the controls with runat="server". I tried using

ControlCollection myControls = Page.Controls

to get them, but I looked at myControls in debug mode and it seems to get a small number of controls, maybe only the controls declared with the asp specific notation , not sure about it.

With said List i would simply do a foreach cycle and add the readonly attribute to each, with a few lines of code. Ideas? (Or maybe I'm just dumb and wasn't able to navigate and search trough myControls in the right way =D )

Fabio Lolli
  • 859
  • 7
  • 23
  • Have you tried FindControl in a recursive function? – Francisco Goldenstein Jul 16 '15 at 15:30
  • possible duplicate of [C# Get all web controls on page](http://stackoverflow.com/questions/7362482/c-sharp-get-all-web-controls-on-page) – Robert McKee Jul 16 '15 at 15:33
  • @FranciscoGoldenstein I haven't tought of that... But how should i manage the id parameter the method requires? Were you suggesting to try to input every possible id? I could optimize it by adding different prefixes, but it seems to be pretty resource heavy. – Fabio Lolli Jul 16 '15 at 15:34
  • @RobertMcKee I tried that solution and I don't think it works – Fabio Lolli Jul 16 '15 at 15:35
  • Note that, for ASP.NET web forms to recognize a control server-side, it must have `runat="server"`. The client-side id is in the `ClientID` property if memory serves correctly. – Andrew Jul 16 '15 at 15:35
  • @Andrew Yep, every control has runat="server" – Fabio Lolli Jul 16 '15 at 15:36
  • Would this be of some help in regards to getting all the controls recursively? http://stackoverflow.com/questions/7362482/c-sharp-get-all-web-controls-on-page – haku Jul 16 '15 at 15:37
  • @NoSaidTheCompiler I will double check, maybe I missed something and it didn't work because of that :) But the problem I think is a can't be recognized by specifying the control type, like TextBox or DropDownList... If these were asp controls it would be perfect – Fabio Lolli Jul 16 '15 at 15:41
  • They would be HtmlInputText controls. Or just specify Control, and look at the results in the debugger to limit the results to just those control types. – Robert McKee Jul 16 '15 at 15:47
  • @FabioLolli, this might be what you are looking for..http://stackoverflow.com/questions/4955769/better-way-to-find-control-in-asp-net – haku Jul 16 '15 at 15:54

3 Answers3

1

Taken from: Get All Web Controls of a Specific Type on a Page

/// <summary>
/// Provide utilities methods related to <see cref="Control"/> objects
/// </summary>
public static class ControlUtilities
{
    /// <summary>
    /// Find the first ancestor of the selected control in the control tree
    /// </summary>
    /// <typeparam name="TControl">Type of the ancestor to look for</typeparam>
    /// <param name="control">The control to look for its ancestors</param>
    /// <returns>The first ancestor of the specified type, or null if no ancestor is found.</returns>
    public static TControl FindAncestor<TControl>(this Control control) where TControl : Control
    {
        if (control == null) throw new ArgumentNullException("control");

        Control parent = control;
        do
        {
            parent = parent.Parent;
            var candidate = parent as TControl;
            if (candidate != null)
            {
                return candidate;
            }
        } while (parent != null);
        return null;
    }

    /// <summary>
    /// Finds all descendants of a certain type of the specified control.
    /// </summary>
    /// <typeparam name="TControl">The type of descendant controls to look for.</typeparam>
    /// <param name="parent">The parent control where to look into.</param>
    /// <returns>All corresponding descendants</returns>
    public static IEnumerable<TControl> FindDescendants<TControl>(this Control parent) where TControl : Control
    {
        if (parent == null) throw new ArgumentNullException("control");

        if (parent.HasControls())
        {
            foreach (Control childControl in parent.Controls)
            {
                var candidate = childControl as TControl;
                if (candidate != null) yield return candidate;

                foreach (var nextLevel in FindDescendants<TControl>(childControl))
                {
                    yield return nextLevel;
                }
            }
        }
    }
}

Then do something like:

foreach(var ctrl in Page.FindDescendants<HtmlInputText>())
{
    ctrl.Attributes.Add("readonly","readonly");
}
Community
  • 1
  • 1
Robert McKee
  • 21,305
  • 1
  • 43
  • 57
0

Add this function on your page:

void whatYouWannaDo (Control con)
{
    foreach (Control c in con.Controls)
    {
      if (c.Controls.Count > 0)
          whatYouWannaDo(c);
      else
         {
           //Do stuff here
         }
    }
}

You can do whatever you want in this recursive function. and call this by putting whatYouWannaDo(Page.Controls)

User2012384
  • 4,769
  • 16
  • 70
  • 106
  • Doesn't work, invalid argument error. Suppose it's because Page.Controls is a collection while Control a single occurrence. I will try to adapt this... – Fabio Lolli Jul 16 '15 at 15:51
  • `void DoWhatYouWannaDo2(ControlCollection controls) { foreach (Control c in controls) { if (c.Controls.Count > 0) DoWhatYouWannaDo2(c.Controls); else { **StartToDoWhatYouWannaDoHere** } } }` – mjb Oct 16 '19 at 07:38
0

Apologies for VB.NET. I do this with some extension methods. You also need to pick up an Each extension method on IEnumerable from nuget (try MoreLinq):

    ''' <summary>
    ''' Returns the control and all descendants as a sequence
    ''' </summary>
    <Extension>
    Public Iterator Function AsEnumerable(control As Control) As IEnumerable(Of Control)
        Dim queue = New Queue(Of Control)
        queue.Enqueue(control)

        Do While queue.Count <> 0
            control = queue.Dequeue()
            Yield control
            For Each c As Control In control.Controls
                queue.Enqueue(c)
            Next
        Loop
    End Function

    <Extension>
    Public Sub SetInputControlsToReadonly(control As Control)
        control.AsEnumerable().Each(Sub(c)
                                        If TypeOf c Is TextBox Then DirectCast(c, TextBox).ReadOnly = True
                                        If TypeOf c Is ListControl Then DirectCast(c, ListControl).Enabled = False
                                    End Sub)
    End Sub

This allows you to call control.SetInputControlsToReadonly(). Sometimes you don't want to set all controls to readonly, only a section on the page. In this case wrap the controls in a (or use a Panel), and call SetInputControlsToReadonly on that.

Jay Douglass
  • 4,828
  • 2
  • 27
  • 19
  • The extension method given in http://stackoverflow.com/questions/7362482/c-sharp-get-all-web-controls-on-page is much better than yours since it implements IEnumerable rather than building an entire queue before returning. – Robert McKee Jul 16 '15 at 15:49
  • The extension method I listed returns IEnumerable, and uses an iterator block, so it's still lazy. It doesn't "build up an entire queue before returning". One uses recursion, mine uses iteration. They're both just different ways to walk a tree. – Jay Douglass Jul 16 '15 at 16:19
  • Oh I see. Very interesting, sorry I missed that. If the DOM were being lazily parsed it could make a difference since you enqueue all the children before returning the first, but since I do believe the DOM is already parsed into objects (not lazily), there shouldn't be any significant difference. The recursive method walks it depth-first, yours walks it breadth-first. – Robert McKee Jul 16 '15 at 16:42