0

I'm trying to create a method to simply clear all textboxes in a webform.

This is the code I'm calling:

private void clearFrom()
{
    IEnumerable<TextBox> textBoxes = Controls.OfType<TextBox>();
    foreach (TextBox textBox in textBoxes)
    {
        textBox.Text = string.Empty;
    }
}

It doesn't error, just never gets to call textBox.Text = string.Empty;

I'm guessing the list of textboxes has not been created and suspect I'm missing an important step. I reckon there is something wrong with Controls.OfType<TextBox>()

I also tried using the following:

private void clearFrom()
{
    IEnumerable<TextBox> Textboxes = (from Control c in this.Controls
                                      where c.GetType() == typeof(TextBox)
                                      select c).AsEnumerable().Cast<TextBox>();
    FunctionalExtensions.ForEach(Textboxes, ClearTextBox);
}

public static class FunctionalExtensions
{
    public static void ForEach<T>(IEnumerable<T> items, Action<T> DoSomething)
    {
        foreach (T item in items)
        {
            DoSomething(item);
        }
    }
}

private void ClearTextBox(TextBox txtbox)
{
    txtbox.Text = string.Empty;
}

Again it didn't error but never called ClearTextBox.

I know it's a c# schoolboy error and to be honest the penny hasn't dropped as to what IEnumerable is actually doing. Any help would be appreciated.

Chris Schiffhauer
  • 17,102
  • 15
  • 79
  • 88
ComfortablyNumb
  • 1,448
  • 10
  • 37
  • 64

4 Answers4

2

I think below will help you.It get the all textbox in IEnumerable as per your requirement.

Calling Part

var c = GetAll(this, typeof(TextBox));
        foreach (TextBox txt in c)
        {
            txt.Text = "";
        }

Function

 public IEnumerable<Control> GetAll(Control control, Type type)
    {
        var controls = control.Controls.Cast<Control>();

        return controls.SelectMany(ctrl => GetAll(ctrl, type))
                                  .Concat(controls)
                                  .Where(c => c.GetType() == type);
    }
Pragnesh Khalas
  • 2,908
  • 2
  • 13
  • 26
1

The Controls property only starts at the top. You need to recursively step through each control and it's children to find all the textboxes:

public static List<Control> GetAllControls(List<Control> controls, Type t, Control parent /* can be Page */)
{
foreach (Control c in parent.Controls)
{
if (c.GetType()== t)
controls.Add(c);
if (c.HasControls())
controls = GetAllControls(controls, t, c);
}
return controls;
}
Josh
  • 10,352
  • 12
  • 58
  • 109
  • Here's a SO thread that explains this in more detail: http://stackoverflow.com/questions/4955769/better-way-to-find-control-in-asp-net – Curtis Rutland Feb 04 '14 at 17:33
1

Derivation of Josh's answer using Generics.

public static IEnumerable<T> GetAllControlsOfType<T>(Control parent) where T: Control {
    foreach (Control c in parent.Controls) {
        if (c is T)
            yield return c as T;
        if (c.HasControls())
            foreach (T innerControl in GetAllControlsOfType<T>(c))
                yield return innerControl;
    }
}
Michael Dunlap
  • 4,300
  • 25
  • 36
  • Recursive iterator blocks are rather inefficient. Iterator blocks, and the state machine created to represent them, add quite a bit more overhead than "regular" method calls. It's worthwhile to use an explicit stack to traverse the tree when dealing with iterator blocks. – Servy Feb 04 '14 at 17:42
  • It's easy enough to change then. I'll add a more efficient example. – Michael Dunlap Feb 04 '14 at 17:47
1

The issue is that you're not traversing the entire control's tree. You're just getting the direct children. You can write a simple method to get all of the children through the entire control's tree, plug that into your code, and it'll work.

public static IEnumerable<Control> GetAllChildren(this 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;
    }
}

Using this method you can now write:

private void clearFrom()
{
    var textBoxes = this.GetAllChildren().OfType<TextBox>();
    foreach (TextBox textBox in textBoxes)
    {
        textBox.Text = string.Empty;
    }
}

We can even generalize this to a Traverse method that isn't specific to Control, and that is capable of traversing any tree:

public static IEnumerable<T> Traverse<T>(T item, Func<T, IEnumerable<T>> childSelector)
{
    var stack = new Stack<T>();
    stack.Push(item);
    while (stack.Any())
    {
        var next = stack.Pop();
        yield return next;
        foreach (var child in childSelector(next))
            stack.Push(child);
    }
}

In this case, this would be called as Traverse(this, c => c.Controls), but has the benefit of being usable with any other type of tree.

Servy
  • 202,030
  • 26
  • 332
  • 449