0

I have a winforms app which has to extract text from 50 text boxes found in different tabs and panels. So far i have been unable to find something that works. I have tried:

foreach (Control x in this.Controls)
{
    if (x is NumericTextBox)
    {
       s = i.ToString() + ", " + ((NumericTextBox)x).Text;
       Append_to_Template_File(s);
       i++;
    }
} 

But this only goes through the textboxes on the form I have also found this answer, however I have not managed to make it work: Loop through Textboxes The top answer results in a number of error:

  1. Constraints are not allowed on non-generic declarations
  2. The type or namespace name 'TControl' could not be found

I'm new at using C# and i'm not quite sure how to solve the first error. If it helps, i'm using Visual Studio 2008 and .NET 3.5 Any suggestions?

Community
  • 1
  • 1
  • There is something unclear with your problem. The GUI relationship between `your form`, `tab control` and `panel` can affect how you get the controls you want. – King King Sep 20 '13 at 16:53
  • Make your method recursive. Add a check if x.HasChildren and if so, pass this method x.Controls – sab669 Oct 16 '13 at 20:30

3 Answers3

3

You can use a method such as this to traverse the entire control tree, not just the top level, to get all controls, all the way down:

public static IEnumerable<Control> GetAllChildren(Control root)
{
    var stack = new Stack<Control>();
    stack.Push(root);

    while(stack.Any())
    {
        var next = stack.Pop();
        foreach(Control child in next.Controls)
            stack.Push(child);
        yield return next;
    }
}

You can then filter out the ones of the type that you want and map them each to their text value:

var lines = GetAllChildren(form)
    .OfType<NumericTextBox>()
    .Select((textbox, i) => string.Format("{0}, {1}", i, textbox.Text));

foreach(var line in lines)
    Append_to_Template_File(line);
Servy
  • 202,030
  • 26
  • 332
  • 449
  • Thank you for the solution. It works fantastically. Only problem is the generated text file starts with the textboxes on the last tab. Any idea how i could fix that? I've tried renaming and rearranging the visual studio generated code but that didn't change anything – Vlad Stefan Sep 23 '13 at 08:40
  • Just realized after a few tries: although the first generated textfile always starts with the last tab, after a few more tries it chooses a random tab instead – Vlad Stefan Sep 23 '13 at 09:10
3

Similar to idea of Servy. here is another implementation ;)

The below function gets a control as parameter and returns list of all textboxes inside it as ref parameter l;

 void findall(Control f, ref List<Control> l) {
        foreach (Control c in f.Controls) {
            if (c is TextBox)
                l.Add(c);
            if  (c.HasChildren)
                findall(c, ref l);
        }
    }

and you can call it this way

List l = new List();

findall(this, ref l);

Sali Hoo
  • 743
  • 2
  • 8
  • 22
  • There is no need to pass the list by reference; it's a reference type. Copying the reference is just fine here. There's no need to check if it has children; if it doesn't the foreach loop just won't do anything. Unlike my solution, this is forced to find every single node before any can be used. Likely not an issue here, but potentially an issue in other cases. It also consumes quite a lot more memory (if the control tree is large) as a result of needing to hold all items in memory. There's also no particular *advantage* to this solution. – Servy Sep 20 '13 at 18:01
  • This solution also isn't flexible with respect to the control you're filtering for. You need to write a whole new method from scratch if you want to search for say Buttons instead, since it's not generic. – Servy Sep 20 '13 at 18:03
  • Thanks for commenting that ref is not required ;) I added the check for children to avoid a useless recursive call. I can remember the recursive codes easily and thought maybe some other coders prefer recursive version. making the solution generic is trivial ... Thanks – Sali Hoo Sep 20 '13 at 18:31
0

Recursion is your friend!

 private void DoThings()
 {
  MyFunc(this.Controls);
 }

 private void MyFunc(Control.ControlCollection controls)
 {
      foreach (Control x in this.Controls)
      {
          if (x is NumericTextBox)
          {
             s = i.ToString() + ", " + ((NumericTextBox)x).Text;
             Append_to_Template_File(s);
             i++;
          }

          if (x.HasChildren)
              MyFunc(x.Controls)
      }
 }
sab669
  • 3,984
  • 8
  • 38
  • 75