Let's say I have 7 group boxes but some of them also have group box inside them and some do not.
now if I want to iterate through those 7 group boxes and apply something to them, is there a way that I can exclude those Child group boxes from this loop?
though i question the choice of implementation (can you use polymorphism instead? what exactly are you trying to do?), there is a Parent property, e.g.
void soSomething(Control ctrl)
{
if (ctrl is GroupBox && (ctrl.Parent is null || !(ctrl.Parent is GroupBox)))
{
//do something here
}
foreach(Control child in ctrl.Controls)
{
doSomething(child);
}
}
Mark them with the tag property, or something.
Related
This question already has answers here:
How add or remove object while iterating Collection in C#
(6 answers)
Closed 2 months ago.
I have a StackPanel that holds Usercontrols, these UserControls are replaced, animated, etc on user input. At specific times I would like to make sure that only the currently active view is present in the stackpanel. I tried with a function like this
public void cleanupStackPanel(UserControl ctrl)
{
foreach (UserControl item in contentContainer.Children)
{
if(item != ctrl)
{
contentContainer.Children.Remove(item);
}
}
}
But upon calling, it says "enumerator is not valid because the collection changed". How could I change this to achieve the result I want?
You cannot remove items inside of an foreach loop. Use a for loop instead, but be careful: when removing items you have to manipulate the index parameter too!
public void cleanupStackPanel(UserControl ctrl)
{
for ( int i = 0; i < contentContainer.Children.Count; i++ )
{
var item = (UserControl) contentContainer.Children[i];
if(item != ctrl)
{
contentContainer.Children.Remove(item);
i--;
}
}
}
I could not test this code, because your example is missing of the surrounded class. So I guessed that contentContainer.Children has a Count property ... but instead it could also be Length. But I am sure, you will find the correct way of determining the number of children ;)
If I want to remove all the GroupBox controls, I can use:
foreach (Control c in this.Controls.OfType<GroupBox>().ToList())
{
this.Controls.Remove(c);
}
How can I have an exception here? In other words, I would like to delete all the GroupBox controls except where the name of the GroupBox is "Groupbox1".
An alternative to Rufus's solution if you know the names of the GroupBoxes that you want to exclude beforehand, you can use the Enumerable.Except() method:
foreach (var grp in Controls.OfType<GroupBox>().
Except(new[] { groupBox1, groupBox7 }).ToList())
{
Controls.Remove(grp);
}
You can add a filter to your query to exclude the name of the control you don't want to delete:
foreach (var groupBoxToDelete in Controls.OfType<GroupBox>().ToList()
.Where(ctrl => ctrl.Name != "groupBox1"))
{
Controls.Remove(groupBoxToDelete);
}
I am attempting to validate a forms controls to see if they are empty and found an interesting point in my flailing.
List<string> emptycontrols = new List<string>();
foreach (Control control in Mainform.V_Datafield.Controls)
{
if (control.Text.Contains(null))
{
emptycontrols.Add(control.Name);
}
}
if (emptycontrols.Count > 0)
{
MessageBox.Show("Empty fields detected:", emptycontrols.ToString());
}
Above is my mediocre solution and when run it comes up that a control, namely the DateTimePicker control can never be empty and quite rightly so.
Ultimately my question is how would I exclude the DateTimePicker control from the foreach loop so that it will ignore it but continue to check the other controls?
The groupbox (V_datafield) contains:
10 x TextBoxes
1 x RichTextBox
1 x DateTimePicker as mentioned above.
You can always check like following inside your foreach loop
if (control is DateTimePicker)
continue;
You could use is like this:
foreach (Control control in Mainform.V_Datafield.Controls)
if (!(control is DateTimePicker) && string.IsNullOrEmpty(control.Text))
emptycontrols.Add(control.Name);
Or, actually, your loop could be removed using LINQ to become:
var emptyControls = Mainform.V_Datafield.Controls
.Cast<Control>()
.Where(control => !(control is DateTimePicker))
.Where(control => string.IsNullOrEmpty(control.Text))
.Select(control => control.Name);
using two Where to keep the logic from the previous code but they could be merged using &&.
For example if I want to check if all the input fields are filled, I do not want to do this with a lot of if statements, especially if there are a lot of text fields. So is there a better way?
What about looping through all controls in the form, and get if it's empty or not ?
foreach(Control control in this.Controls)
{
if(control is TextBox && control.Text == "")
{
MessageBox.Show("You have to fill all fields");
return;
}
}
sure you can check for whatever control you want ! not just the textBoxes
With System.Linq you can do it in one line, and filter it on the controls you need:
this.Controls.OfType<TextBox>().All(box => box.Text.Length > 0);
Or for checkbox
this.Controls.OfType<CheckBox>().All(box => box.Checked);
And so on.
It will return true if all is filled/checked.
Just remember to put using System.Linq; on top of your code
On my Visual C# Form application, I have a combobox inside a groupbox to help organize / look neat. However, once I put the combobox inside the groupbox, I am no longer able to find it by looping through all of the controls on my form.
For example, if I run this code with the Combobox inside the Groupbox I get a different result than if its outside the group box:
foreach (Control contrl in this.Controls)
{
richTextBox1.Text += "\n" + contrl.Name;
}
If the combobox is inside the groupbox, it won't find it.
I also noticed in the Form1.Designer.cs file that whenever I add the combobox inside the groupbox, the following line of code appears to the groupbox:
this.groupBox4.Controls.Add(this.myComboBox);
..
this.groupBox4.Location = new System.Drawing.Point(23, 39);
this.groupBox4.Name = "groupBox4";
... etc...
And this line will be removed:
this.Controls.Add(this.myComboBox);
If I try to edit it manually, it automatically switches back once I move the combobox back inside the groupbox.
Any help would be appreciated! Thanks!
Brian
As you said, you added combo box to group box, so it is added to Controls collection of group box and the designer generates this code:
this.groupBox4.Controls.Add(this.myComboBox);
So if you want to find the combo box programmatically, you can use this options:
Why not simply use: this.myComboBox ?
Use var combo = (ComboBox)this.Controls.Find("myComboBox", true).FirstOrDefault();
Use var combo = (ComboBox)this.groupBox4.Controls["myComboBox"]
Also if you want too loop, you should loop over this.groupBox4.Controls using:
foreach(Control c in this.groupBox4.Controls) {/*use c here */}
this.groupBox4.Controls.Cast<Control>().ToList().ForEach(c=>{/*use c here */})
Just like the Form object, the Group object can hold a collection of controls. You would need to iterate through the Group control's controls collection.
One more idea for getting at all or one ComboBox in a GroupBox, in this case groupBox1. Granted Resa's suggestion for using Find with FirstOrDefault would be best to access one combobox.
List<ComboBox> ComboBoxes = groupBox1
.Controls
.OfType<ComboBox>()
.Select((control) => control).ToList();
foreach (var c in ComboBoxes)
{
Console.WriteLine(c.Name);
}
string nameOfComboBox = "comboBox1";
ComboBox findThis = groupBox1
.Controls
.OfType<ComboBox>()
.Select((control) => control)
.Where(control => control.Name == nameOfComboBox)
.FirstOrDefault();
if (findThis != null)
{
Console.WriteLine(findThis.Text);
}
else
{
Console.WriteLine("Not found");
}
You can use the ControlCollections Find Method, it has a parameter that will search the parent and its Children for your control.
ComboBox temp;
Control[] myControls = Controls.Find("myComboBox", true); //note the method returns an array of matches
if (myControls.Length > 0) //Check that it returned a match
temp = (ComboBox)myControls[0]; //use it