Loop through all controls of a Form, even those in GroupBoxes

后端 未结 9 1096
囚心锁ツ
囚心锁ツ 2020-11-29 05:17

I\'d like to add an event to all TextBoxes on my Form:

foreach (Control C in this.Controls)
{
    if (C.GetType() == typeof(System.Windows.Forms         


        
相关标签:
9条回答
  • 2020-11-29 05:45

    Since the Question regarding "Adding an Event to your TextBoxes"; was already answered; I'm providing some explanation and adding an iteration alternative using a for loop instead.


    Problem:

    • Being Unable to Get Controls Inside a Container.


    Solution:

    • In order to retrieve the Controls inside a Container you have to specify the Container that Contains the Controls you wish to access to. Therefore your loop must check the Controls inside a Container.
      Otherwise your loop will not find the Controls inside a Container.

    i.e:

    foreach (Control control in myContainer.Controls)
    {
       if (control is TextBox) { /* Do Something */ }
    }
    
    • In case you have several Containers:
      Initially iterate the Containers.
      Then iterate over the controls inside the container (the container found in the initial iteration).


    Pseudo Code Example on How to use a for Loop Instead:

        /// <summary> Iterate Controls Inside a Container using a for Loop. </summary>
        public void IterateOverControlsIncontainer()
        {
            // Iterate Controls Inside a Container (i.e: a Panel Container)
            for (int i = 0; i < myContainer.Controls.Count; i++)
            {
                // Get Container Control by Current Iteration Index
                // Note:
                // You don't need to dispose or set a variable to null.
                // The ".NET" GabageCollector (GC); will clear up any unreferenced classes when a method ends in it's own time.
                Control control = myContainer.Controls[i];
    
                // Perform your Comparison
                if (control is TextBox)
                {
                    // Control Iteration Test.
                    // Shall Display a MessageBox for Each Matching Control in Specified Container.
                    MessageBox.Show("Control Name: " + control.Name);
                }
            }
        }
    
    0 讨论(0)
  • 2020-11-29 05:46

    you can only loop through open forms in windows forms using form collection for example to set windows start position for all open forms:

    public static void setStartPosition()
            {
                FormCollection fc = Application.OpenForms;
    
                foreach(Form f in fc)
                {
                    f.StartPosition = FormStartPosition.CenterScreen;
                }
            }
    
    0 讨论(0)
  • 2020-11-29 05:47

    Try this

    AllSubControls(this).OfType<TextBox>().ToList()
        .ForEach(o => o.TextChanged += C_TextChanged);
    

    where AllSubControls is

    private static IEnumerable<Control> AllSubControls(Control control)
        => Enumerable.Repeat(control, 1)
           .Union(control.Controls.OfType<Control>()
                                  .SelectMany(AllSubControls)
                 );
    

    LINQ is great!

    0 讨论(0)
  • 2020-11-29 05:49

    A few simple, general purpose tools make this problem very straightforward. We can create a simple method that will traverse an entire control's tree, returning a sequence of all of it's children, all of their children, and so on, covering all controls, not just to a fixed depth. We could use recursion, but by avoiding recursion it will perform better.

    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 we can get all of the children, filter out those of the type we need, and then attach the handler very easily:

    foreach(var textbox in GetAllChildren().OfType<Textbox>())
        textbox.TextChanged += C_TextChanged;
    
    0 讨论(0)
  • 2020-11-29 05:51

    Haven't seen anyone using linq and/or yield so here goes:

    public static class UtilitiesX {
    
        public static IEnumerable<Control> GetEntireControlsTree(this Control rootControl)
        {
            yield return rootControl;
            foreach (var childControl in rootControl.Controls.Cast<Control>().SelectMany(x => x.GetEntireControlsTree()))
            {
                yield return childControl;
            }
        }
    
        public static void ForEach<T>(this IEnumerable<T> en, Action<T> action)
        {
            foreach (var obj in en) action(obj);
        }
    }
    

    You may then use it to your heart's desire:

    someControl.GetEntireControlsTree().OfType<TextBox>().ForEach(x => x.Click += someHandler);
    
    0 讨论(0)
  • 2020-11-29 05:51

    As you have stated, you will have to go deeper than just cycling over each element in your form. This, unfortunately, implies the use of a nested loop.

    In the first loop, cycle through each element. IF the element is of type GroupBox, then you know you'll need to cycle through each element inside the groupbox, before continuing; else add the event as normal.

    You seem to have a decent grasp of C# so I won't give you any code; purely to ensure you develop all the important concepts that are involved in problem solving :)

    0 讨论(0)
提交回复
热议问题