foreach control c# skipping controls - c#

I have the following loop to remove the buttons in my C# Windows Forms application. The only problem is that it skips every other button. How do I go about removing all the button controls from my form?
foreach (Control cntrl in Controls)
{
if(cntrl.GetType() == typeof(Button))
{
Controls.Remove(cntrl);
cntrl.Dispose();
}
}

I think this way is a bit more readable:
var controlsToRemove = Controls.OfType<Button>().ToArray();
foreach (var control in controlsToRemove)
{
Controls.Remove(control);
cntrl.Dispose();
}
Calling ToArray() makes a new concrete collection, so that you can enumerate over one and modify the other.

Surprised that's not erroring on you, since you're modifying the collection as you're iterating over it. Use a for loop and start at the end:
for (int ii = Controls.Count - 1; ii >= 0; ii--)
{
Control cntrl = Controls[ii];
Controls.remove(cntrl);
cntrl.Dispose();
}
(Starting at the end because otherwise you'd be changing the indexes of each control as you iterated.)

Youre iterating over the same collection from whitch youre removing. Use this code:
List<Control> cleanControls = new List<Control>();
foreach(Control ctr in Controls)
{
if(cntrl.GetType() != typeof(Button))
{
cleanControls.Add(ctr);
}
else
{
ctr.Dispose();
}
}
Controls = cleanControls;
That's It!
Hope I helped!

Related

VisualStudio c# foreach on checkbox

I have this code and it seems like it should work but for some reason it doesnt.
foreach(Control c in Controls.OfType<CheckBox>()) {
Check_checked += 1;
}
** Check edit: When I step through the code the Control c is picking up all of the textboxes but nothing else.
Any help would be appreciated.
**I realise that ofType should not be picking up text/labels/watever.
Im getting text/labels/watever.
I moved my code to another computer also running visual studio. It doesnt pickup checkboxes and it doesnt seem to be bugging about picking up text/label/watever on that system.
So I think one of the issues is my VS is bugger-up. Will re-install now.
look at following answer
Get all controls of a specific type
Code check if the control is a ContainerControl and then iterates over all the children of that control to find the controls of type.
public static IEnumerable<T> GetControlsOfType<T>(Control root)
where T : Control
{
var t = root as T;
if (t != null)
yield return t;
var container = root as ContainerControl;
if (container != null)
foreach (Control c in container.Controls)
foreach (var i in GetControlsOfType<T>(c))
yield return i;
}
Then you could do something like this:
foreach (var pictureBox in GetControlsOfType<CheckBox>(form)) {
}
This code is a simple solution for counting checkboxes on a form that are checked.
private int CountChecks(IEnumerable controls)
{
var result = 0;
foreach (Control xControl in controls)
{
if (xControl.HasChildren) result += CountChecks(xControl.Controls);
if (!(xControl is CheckBox)) continue;
if (!(xControl as CheckBox).Checked) continue;
result++;
}
return result;
}
you might use this in this manner:
var howManyAreChecked = CountChecks(Controls);
This would have to be in a form to use this syntax. You must pass a forms Controls into the method in order to work correctly.

get all controls of a type and change their properties

in my software I have a TabControl and I want to search for all Controls of a certain type using foreach (for example) and change some of there properties.
Now when I do something like this:
Control ctrl;
ctrl = My_CheckedListBox;
((CheckedListBox)ctrl).SetItemChecked(0, false);
It works fine and the checkboxes all get unchecked, no problem. But when I use foreach they don't:
foreach (Control item in ModuleTab.Controls)
{
if (item is CheckedListBox)
{
for (int i = 0; i < ((CheckedListBox)item).Items.Count; i++)
{
((CheckedListBox)item).SetItemChecked(i, false);
}
}
}
I know it is because item is not really the Control but an object. I wonder if there is something like:
foreach (Control ref item in ModuleTab.Controls)
Any help?
So I solved it! Jon Skeet was right. The Tab in the TabControl didn't contain the controls I was looking for because they were all in a GroupBox!
I searched for them in the GroupBox and there they were. The CheckBoxes where unchecked and everything worked perfectly as it should.
#Jon Thx for the "observing" tip. I let the program show me the available Controls in the Tab using a MessageBox and that is how I solved it. Thx also for the user who deleted his answer because he interduced me to the OfType<>() method.That really made the code look better:
foreach (var groupbox in ModuleTab.Controls.OfType<GroupBox>())
{
foreach (var item in groupbox.Controls.OfType<CheckedListBox>())
{
for (int i = 0; i < item.Items.Count; i++)
{
item.SetItemChecked(i, false);
}
}
}
foreach (Control item in ModuleTab.Controls)
{
if (item.GetType() == typeof(CheckedListBox)))
{
for (int i = 0; i < item.Items.Count; i++)
{
item.SetItemChecked(i, false);
}
}
}

Default control collection

When I create & add a control to my WinForm using the designer, is my control automatically added to a collection with all the others somewhere ?
Let's say there are like 20 TextBox and I need to clear them all at the same time without calling it like so :
txtbox1.Clear();
txtbox2.Clear();
txtbox3.Clear();
...
I know I should have created manually each control without the designer and add them in a collection but it's too late for that now. So any idea if I can access the whole group of controls ?
try this
private void ClearTextBoxes()
{
Action<Control.ControlCollection> func = null;
func = (controls) =>
{
foreach (Control control in controls)
if (control is TextBox)
(control as TextBox).Clear();
else
func(control.Controls);
};
func(Controls);
}
Oh I actually found out how to do this just after I wrote my question.
I can use a foreach loop on this.controls.
Then I test if the control is a TextBox.
foreach (Control x in this.Controls)
{
if (x is TextBox)
{
((TextBox)x).Text = String.Empty;
}
}

Close all open forms except the main menu in C#

Trying to close all forms except for the main menu using
FormCollection formsList = Application.OpenForms;
with a foreach loop and saying,
if (thisForm.Name != "Menu") thisForm.Close();
Which works ok, it skips the menu, and closes the first, but it then errors:
Collection was modified; enumeration operation may not execute
and stops. I have tried a few places, and they all say that this foreach loop is the way to do it, and it is especially annoying as I am not updating my forms list after closing the forms, which I thought might work. The only thing I could think of was to start at the back and work forward using a while.
If you use foreach to enumerate through a collection, it can't be modified (items added or removed) during the iteration. Try copying references to the forms to another collection, and then remove them by iterating through that collection.
In situations like this, you can use a list or a simple array, such as:
List<Form> openForms = new List<Form>();
foreach (Form f in Application.OpenForms)
openForms.Add(f);
foreach (Form f in openForms)
{
if (f.Name != "Menu")
f.Close();
}
Or you can use a for loop:
for (int i = Application.OpenForms.Count - 1; i >= 0; i--)
{
if (Application.OpenForms[i].Name != "Menu")
Application.OpenForms[i].Close();
}
Or, my new and current favorite, you can use the Reverse() method:
foreach (Form f in Application.OpenForms.Reverse())
{
if (f.Name != "Menu")
f.Close();
}
Here's an even more concise method that uses the same number of lines as your original method:
Form[] forms = Application.OpenForms.Cast<Form>().ToArray();
foreach (Form thisForm in forms)
{
if (thisForm.Name != "Menu") thisForm.Close();
}
By using Linq's extension method Cast, you can avoid looping through the collection to build an array.
That happens when the collection is changed inside a foreach loop that uses it. You are removing an item from formsList inside the loop.
Try this:
for (int i = formsList.Count-1; i > 0; i--)
{
if (formsList[i].Name != "Menu")
{
formsList[i].Close();
}
}
To Close all forms :
for (int i = Application.OpenForms.Count - 1; i >= 0; i--)
{
if (Application.OpenForms[i].Name != "Menu")
Application.OpenForms[i].Close();
}
I know this is old but I needed to perform this same scenario and came up with a elegant and simple way to achieve this as follows
Form[] formsList = Application.OpenForms.Cast<Form>().Where(x => x.Name == "Form1").ToArray();
foreach (Form openForm in formsList)
{
openForm.Close();
}
This will close ALL windows that where opened called Form1
As the error states, you can't modify a collection in its foreach.
Instead, you can use a backwards for loop.
as the form collection is updating for every iteration. When you close a form, it is removed from the form collection. it's like removing a object from memory while it is using .

Looping through controls in ASP.Net C#

I have a page, which contains a table, with a couple of rows, and in that row there are checkboxes.
Now the thing I want, is to loop trough all checkboxes to see if they are checked or not.
This is my current approach:
foreach (Control c in Page.Controls)
{
if(c is Checkbox){
}
}
Now the problem is that I receive only 2 controls, the page and the Table. So the checkboxes are in:
Table -> TableRow -> TableCell -> CheckBox
Is there a way to get ALL controls on a page, instead of having to nest into it to get out the controls?
control.Controls will return the first level child controls only. For details, check this question.
Since the controls are hierarchical, every control sees only it's child controls. You have to iterate through every control to get them all.
You can find an example on how to do it here:
http://www.atrevido.net/blog/CommentView,guid,c792adbf-ce0a-4bf9-a61c-ca1a4296d0ea.aspx
A Control can act as a parent to a collection of controls as in your case .You should Iterate through the child of the parent control you are using in you page.
refer http://msdn.microsoft.com/en-us/library/system.windows.forms.control.controls%28VS.71%29.aspx
I just did a nested foreach loop like this:
List<Control> allControls = new List<Control>();
List<string> selectedIDs = new List<string>();
foreach (Control c in this.pnlTable.Controls)
{
allControls.Add(c);
if (c.Controls.Count > 0)
{
foreach (Control childControl in c.Controls)
{
allControls.Add(childControl);
if (childControl.Controls.Count > 0)
{
foreach (Control childControl2 in childControl.Controls)
{
allControls.Add(childControl2);
if (childControl2.Controls.Count > 0)
{
foreach (Control childControl3 in childControl2.Controls)
{
allControls.Add(childControl3);
}
}
}
}
}
}
}
foreach (Control control in allControls)
{
if (control is CheckBox)
{
if (((CheckBox)(control)).Checked)
{
selectedIDs.Add(((CheckBox)(control)).ID);
}
}
}
Depending of the depth of the control I added a if and foreach..
Hope this helps someone else with the same issue...

Categories

Resources