-1

I have a winforms project with a multi-level container setup in place. As in, I have a set of Panels on the top layer, each of those Panels has another set of Panels nested within them, and each of those sub-panels have a set of Controls (TextBoxes, CheckBoxes, etc.) in each one.

What I want is to be able to retrieve Controls of a certain type, given only the top level Panel. For example, one set of this using the names in my project would be MainPanelTruck which has a PanelTruckCheck Panel under it, which itself has 8 CheckBox nested in it. I want to be able to retrieve those 8 CheckBox given just MainPanelTruck.

Here's an image of a section of the Panel structure for reference.

I have been trying to get OfType<>() to work but as far as I can tell, it only searches among the next level down, so when I search for CheckBox using it, I get nothing as a result, because it only looks at the sub-panels.

This would be a lot easier if the Find method in ControlCollection allowed for a predicate or condition instead of a specific string as key, because it has the searchAllChildren bool which would be very handy here.

I can think of many ways I can get the items I want here, but none of them feel particularly elegant, which is what I'm seeking here. Thanks :)

2 Answers2

1

You can write a simple (extension) method that returns all nested controls of given control:

public static class ControlExtensions
{
    public static IEnumerable<Control> GetAllNestedControls(this Control root)
    {        
        var stack = new Stack<Control>();
        stack.Push(root);

        do
        {
            var control = stack.Pop();

            foreach (Control child in control.Controls)
            {
                yield return child;
                stack.Push(child);
            }
        }
        while (stack.Count > 0);
    }
}

With this in hand getting all checkboxes is easy:

panel1.GetAllNestedControls().OfType<CheckBox>()

You can also pass an optional boolean flag to search all children if you want. Check the flag before pushing child controls to stack. I would rename the method in this case to the name suggested by 00110001:

IEnumerable<Control> EnumerateControls(this Control root, bool searchAllChildren)

Usage would be

 panel1.EnumerateControls(searchAllChildren: true).OfType<CheckBox>()
Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
1

If I understand what you are asking, you want all controls of a certain type in a given parent container and include all sub containers

Given

public IEnumerable<T> EnumerateControls<T>(Control control) where T : Control
{
   var queue = new Queue<Control>(new []{ control });
   while (queue.Any())
   {
      var controls = queue.Dequeue().Controls;

      foreach (var item in controls.OfType<T>())
         yield return item;

      foreach (Control subControl in controls)
         queue.Enqueue(subControl);
   }
} 

Usage

var allCheckBoxes = EnumerateControls<CheckBox>(somePanel);
TheGeneral
  • 79,002
  • 9
  • 103
  • 141