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.
Related
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);
}
}
}
I've found a few answers around that work fine with modifying .Text, .Checked values and so, but none of them worked when I tried changing the .Value property. I can't get that to work on progress bars.
Last I tried:
foreach (Control c in this.Controls)
{
if (c.Name == "test" && c is ProgressBar)
{
((ProgressBar)c).Value = 23;
}
}
Am I missing a using statement or something?
Assuming that your progressbar control is named "test" (all lowercase letters) and is placed directly on the surface of your form (not inside a groupbox,panel or other control container) then this code should work and simplify your work
foreach (var c in this.Controls.OfType<ProgressBar>().Where(x => x.Name == "test")
{
c.Value = 23;
}
instead if the ProgressBar is placed inside a control container (like a panel) the above code should be changed to loop over the controls collection of the container
foreach (var c in this.panel1.Controls.OfType<ProgressBar>().Where(x => x.Name == "test")
{
c.Value = 23;
}
As pointed out in the comment by KingKing, if you are absolutely sure that a control named "test" exists in your groupbox then a simple lookup in the controls collection should result in your progressbar. Looping is not necessary in this case
ProgressBar pb = this.groupBox1.Controls["test"] as ProgressBar;
if(pb != null) pb.Value = 23;
The trick here is that Controls is not a List<> or IEnumerable but a ControlCollection.
I recommend using an extension of Control. Add this class to your project:
public static class ControlExtensionMethods
{
public static IEnumerable<Control> All(this System.Windows.Forms.Control.ControlCollection controls)
{
foreach (Control control in controls)
{
foreach (Control grandChild in control.Controls.All())
yield return grandChild;
yield return control;
}
}
}
Then you can do :
foreach(var textbox in this.Controls.All())
{
// Apply logic to a control
}
Source: Click
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!
I've used this code before in another program, but now I'm having trouble understanding why it won't run the code after my second line.
foreach (Control c in Controls)
if (c.GetType() == typeof(TextBox)) //doesn't run any further
{
if ((string)c.Tag == "Filled")
{
...
}
...
}
I'm either missing some minor little detail or something else is incorrect. Any ideas?
EDIT: my textboxes are inside a panel.
It might be simpler to do this:
foreach ( TextBox tb in this.Controls.OfType<TextBox>())
{
if ((string)tb.Tag == "Filled")
// .....
}
When you call Control.Controls, it will only return the controls at the outermost level. It won't recursively descend into any container controls that hold other controls.
If your controls are in another container, you will need to use that container's .Controls property instead.
Alternatively you can generalize it by writing a method to recursively return all the controls from the parent and all it's children, like so:
public IEnumerable<Control> AllControls(Control container)
{
foreach (Control control in container.Controls)
{
yield return control;
foreach (var innerControl in AllControls(control))
yield return innerControl;
}
}
You can then use that instead of Control.Controls as follows:
private void test() // Assuming this is a member of a Form other class derived from Control
{
var textboxesWithFilledTag =
AllControls(this).OfType<TextBox>()
.Where(tb => (string) tb.Tag == "Filled");
foreach (var textbox in textboxesWithFilledTag)
Debug.WriteLine(textbox.Text);
}
As the comment says, I'm assuming that the test() method is a member of your Form or another class derived from Control. If it isn't, you will have to pass the parent control to it:
private void test(Control container)
{
var textboxesWithFilledTag =
AllControls(container).OfType<TextBox>()
.Where(tb => (string) tb.Tag == "Filled");
foreach (var textbox in textboxesWithFilledTag)
Debug.WriteLine(textbox.Text);
}
The following method has identical results to the one above, for reference (and is more readable IMHO):
private void test(Control container)
{
foreach (var textbox in AllControls(container).OfType<TextBox>())
if ((string)textbox.Tag == "Filled")
Debug.WriteLine(textbox.Text);
}
For your code, your button click handler might look something like this:
void button1_Click(object sender, EventArgs e)
{
foreach (var c in AllControls(this).OfType<TextBox>())
{
if ((string) c.Tag == "Filled")
{
// Here is where you put your code to do something with Textbox 'c'
}
}
}
Note that you also need the AllControls() method, of course.
To get all controls (not only the direct children of the form) you can use this recursive Linq
Func<Control, IEnumerable<Control>> allControls = null;
allControls = c => new Control[] { c }
.Concat(c.Controls.Cast<Control>()
.SelectMany(x=>allControls(x)));
Now you can filter the TextBoxes
var tbs = allControls(this).OfType<TextBox>()
.Where(t=>(string)t.Tag=="Filled")
.ToList();
Better use if (c is TextBox).
Furthermore, if you want to know why your code breaks, use try/catch
I'd recommend to use following syntax:
foreach (Control c in Controls)
if (c is TextBox)
Are you setting tag property from yourself. This is a string type of property.so you can try this:
if (c.Tag == "Filled")
{
Console.WriteLine(c.Name);
}
if you want to check that text box is not empty then you can simply try this :
if (c.Text.Trim().Length == 0)
{
Console.WriteLine(c.Name);
}
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;
}
}