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;
}
}
Related
I am trying to clear the images from all the picture boxes on a single click.
foreach (Control x in this.Controls)
{
if (x is PictureBox)
{
x.Image = null;
}
}
I am getting this error:
Thanks for the help.
Just use the Controls.OfType<> method so you get only PictureBoxes from the Form:
foreach(PictureBox pb in this.Controls.OfType<PictureBox>())
{
pb.Image = null;
}
It is obvious, Control class does not have a property with the name Image. You need to cast the control to a PictureBox object, like this:
foreach (Control control in this.Controls) // renamed x to control (with a small c), which enhances the readability
{
if (control is PictureBox pictureBox) // As #EtiennedeMartel suggested, this is a neat and efficient way of achieving the desired. Use this please.
{
pictureBox.Image = null;
}
}
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);
}
Suppose I don't want to use
if (string.IsNullOrEmpty(textbox1.Text))
{
textbox1.Text = null;
}
for every textbox controls in form, is there a easier way to do it ?
Simple way is Loop through every control, see the below code
foreach (Control C in this.Controls)
{
if (C is TextBox)
{
if (C.Text == "")
{
C.Text = null;
}
}
}
It is one more way
foreach(Control txt in this.Controls)
{
if(txt.GetType() == typeof(TextBox))
if(string.IsNullOrEmpty(txt.Text))
txt.Text = null;
}
Hope it helps
You can iterate through the ControlCollection of the given form, e.g. frmMain.Controls
Now this will be the basic Control object, so you would need a test to see if it is of type TextBox.
.NET 2.0 - you'll have to check this manually
.NET 3.0+ - use the .OfType<TextBox> extension method to give you only a list of IEnumerable<TextBox>
Note that iterating through this from the form will only give you text boxes on that form. If you bind text boxes to a container it won't show up there.
Safest bet would be to write a recursive function that walks through all the control collections and passes the reference to your test function to perform your test and update.
Try this:
foreach(Control c in this.Controls)
{
if (c.GetType().FullName == "System.Windows.Forms.TextBox")
{
TextBox t = (TextBox)c;
t.Clear();
}
}
You can create a derived control from textbox control, and override its text property.