0

Linq has always befuddled me. I am trying to extract all controls from an ASP.Net form page where the ID of the control contains a specific string. The control collection is hierarchical and I want to return any matching controls from all levels. Am I anywhere in the ballpark here? I could really use some help/education. The collection parameter is the collection of controls from the page and controlID is the text I am searching for.

    public static Control FindControlsByControlID(ControlCollection collection, string controlID)
    {
        IEnumerable<Control> controls = collection.Cast<Control>();
        IEnumerable<Control> matchedControls = controls
            .SelectMany(p => p.Controls.Cast<Control>()
                .SelectMany(c => c.Controls.Cast<Control>())
                .Where(d => d != null ? d.ID != null ? d.ID.Contains(controlID) : false : false))
            .Where(a => a != null ? a.ID != null ? a.ID.Contains(controlID) : false : false);

        ConcurrentQueue<Control> cq;
        if (matchedControls != null)
            cq = new ConcurrentQueue<Control>(matchedControls);
        else
            return null;
        ...

Thanks in advance!

tjams
  • 3
  • 1
  • What you have should work, but no need to test at each `SelectMany` level, just test at the end. Also, use `&&` instead of `?:`. But you will only go two levels deep with this. – NetMage Apr 13 '20 at 20:07
  • `Forms` have `Name`s, not `ID`s? Does this code actually compile? – NetMage Apr 13 '20 at 20:11

1 Answers1

0

Use an extension method to get all child controls:

public static class ControlExt {
    public static IEnumerable<Control> AndSubControls(this Control aControl) {
        var work = new Queue<Control>();
        work.Enqueue(aControl);
        while (work.Count > 0) {
            var c = work.Dequeue();
            yield return c;
            foreach (var sc in c.Controls.Cast<Control>()) {
                yield return sc;
                if (sc.Controls.Count > 0)
                    work.Enqueue(sc);
            }
        }
    }
}

Now you can test all the subcontrols in your ControlCollection:

IEnumerable<Control> matchedControls = controls.SelectMany(c => c.AndSubControls())
                                               .Where(a => a != null && a.ID != null && a.ID.Contains(controlID));
NetMage
  • 26,163
  • 3
  • 34
  • 55
  • In the last line above, you used a.Name instead of a.ID, but otherwise this worked well. Accepted this as the answer. – tjams Apr 28 '20 at 18:18
  • @tjams Sorry, I changed it. I used `Name` because `Systems.Windows.Forms.Control` doesn't have an `ID` property... I didn't notice you were using Web Forms. – NetMage Apr 29 '20 at 22:28