How to remove all controls except one? - c#

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);
}

Related

How to exclude a particular kind of control from a foreach loop?

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 &&.

Cannot Controls.Find a ComboBox inside a GroupBox

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

How to get a value from a hashtable entry

I have put all of my form controls in a hashtable thus :-
foreach (Control c in this.Controls)
{
myhash.Add(c.Name, c);
}
amongst which are two radio buttons. I would like to get the value of the buttons, ie checked or unchecked, and assign them to a variable. How can I do that please. Thanks for all and any help.
foreach (Control c in hashtable.Values)
{
if(c is RadioButton)
{
string name = x.Name;
bool isChecked = (c as RadioButton).Checked;
}
}
or if you know the name
(hashtable["name"] as RadioButton).Checked;
You can retrieve a value by a key associated with it, basically control Name is a key in hashtable you've created. So if you know a name of controls you need to access:
var control = hash[radioButtonControlName] as RadioButton;
Otherwise using LINQ OfType() and List.ForEach():
// OfType() does check whether each item in hash.Values is of RadioButton type
// and return only matchings
hash.Values.OfType<RadioButton>()
.ToList()
.ForEach(rb => { bool isChecked = rb.Checked } );
OR using foreach loop:
(there is a nice overview of misconception of the List.ForEach() usage)
var radioButtons = hash.Values.OfType<RadioButton>();
foreach(var button in radioButons)
{
bool isChecked = rb.Checked;
}
Cast the control that is the radio button to a RadioButton Class instance and then look at the checked property. At least that would be how I've done this many times over in WebForms using similar classes.
Assuming the hashtable in your code is an instance of Hashtable:
Hashtable myhash= new Hashtable();
foreach (Control c in this.Controls)
{
myhash.Add(c.Name, c);
}
You can do this:
foreach (DictionaryEntry entry in myhash)
{
RadioButton rb = entry.Value as RadioButton;
if (rb != null)
bool checked = rb.Checked;
}
Also you can see the key of the hashmap entry with:
foreach (DictionaryEntry entry in myhash)
{
var componentName = entry.Key;
}
That will correspond with the name of the component that you put in the hashmap (c.Name).
Hope this help you.

Excluding the GroupBoxes that are inside another GroupBox

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.

How do you access a Control in a collection by its Type?

How does one target a control by its Type?
I have a Control collection "TargetControls"
List<Control> TargetControls = new List<Control>();
foreach (Control page in Tabs.TabPages)
{
foreach (Control SubControl in page.Controls)
TargetControls.Add(SubControl);
}
foreach (Control ctrl in TargetControls)...
I need to access each existing control (combobox,checkbox,etc.) by its specific Type with access to its specific properties. The way I'm doing it now only gives me access to generic control properties.
Can't I specify something like...
Combobox current = new ComboBox["Name"]; /// Referencing an Instance of ComboBox 'Name'
and then be given access to it's (already existing) properties for manipulation?
You can use the is keyword to check for a specific type of the control. If the control is of a specific type, do a typecast.
foreach (Control SubControl in page.Controls)
{
if (SubControl is TextBox)
{
TextBox ctl = SubControl as TextBox;
}
}
You can use the OfType<T> extension method:
foreach (var textBox = page.Controls.OfType<TextBox>()) {
// ...
}
You'll need to cast the control to the right type of control before accessing any specific parameters.
ComboBox c = ctrl as ComboBox;
If (c != null)
{
//do some combo box specific stuff here
}
Also you could add the controls to a generic dictionary<string, control> and use the control.name as the key there.
Ex.
Dictionary<string, Control> TargetControls = new Dictionary<string, Control>();
Assuming you can use LINQ, and you're looking for (say) a Button control:
var button = (from Control c in TargetControls
where c.Name == "myName" && c is Button
select c
).FirstOrDefault();
...which will give you the first Button control named "myName" in your collection, or null if there are no such items present.
What about the Find method?
Button btn = (Button)this.Controls.Find("button1", true)[0];
btn.Text = "New Text";
In order to access a control's specific properties, you have to cast it to its appropriate type. For example, if the item in your TargetControls collection was a textbox, you would have to say ((TextBox)TargetControls[0]).Text = 'blah';
If you don't know the types ahead of time, you can use reflection to access the properties, but I'd need to have a better example of what you're trying to do first...

Categories