I have a form that has many dynamically generated checkboxes. At runtime, how can I iterate through each of them so I can get their value and IDs?
foreach(Control c in this.Controls)
{
if(c is CheckBox)
{
// Do stuff here ;]
}
}
I use a simple extension method that will work for any control type:
public static IEnumerable<T> AllControls<T>(this Control startingPoint) where T : Control
{
bool hit = startingPoint is T;
if (hit)
{
yield return startingPoint as T;
}
foreach (var child in startingPoint.Controls.Cast<Control>())
{
foreach (var item in AllControls<T>(child))
{
yield return item;
}
}
}
Then, you can use it like so:
var checkboxes = control.AllControls<CheckBox>();
Using IEnumerable lets you choose how to store the results, and also lets you use linq:
var checkedBoxes = control.AllControls<CheckBox>().Where(c => c.Checked);
If it is Windows Forms, you can try something like this:
private void button1_Click(object sender, EventArgs e)
{
Dictionary<string, bool> checkBoxes = new Dictionary<string, bool>();
LoopControls(checkBoxes, this.Controls);
}
private void LoopControls(Dictionary<string, bool> checkBoxes, Control.ControlCollection controls)
{
foreach (Control control in controls)
{
if (control is CheckBox)
checkBoxes.Add(control.Name, ((CheckBox) control).Checked);
if (control.Controls.Count > 0)
LoopControls(checkBoxes, control.Controls);
}
}
Remember that container controls can contain children, so you might want to check those too.
Like this, maybe (if it's in Windows Forms):
foreach(var checkBox in myForm.Controls.OfType<CheckBox>())
{
//Do something.
}
When they are created, get a list of references to the values, and then you can iterate over the list.
I know that this is old, but It was easy as I can imagine.
Just add all checkboxes into a List<Checkbox>, all checkboxes state are in the list and even if they change in the UI in the list changes too.
List<Checkbox> checkboxes = new List<Checkboxes>();
checkboxes.Add(chk1);
checkboxes.Add(chk2);
//So add all checkboxes you wanna iterate
foreach(Checkbox checkbox in checkboxes){
//Do something using checkbox object
}
Hope this helps :)
Related
I have 15 list box inside my winForm... I am using to clear each of them like below. is there any way to clear them in short way when the application starts?
listBox1.Items.Clear();
listBox2.Items.Clear();
listBox3.Items.Clear();
listBox4.Items.Clear();
listBox5.Items.Clear();
listBox6.Items.Clear();
listBox7.Items.Clear();
listBox8.Items.Clear();
listBox9.Items.Clear();
listBox10.Items.Clear();
parentControl.Controls.OfType<ListBox>().ToList().ForEach(l => l.Items.Clear());
If you want to clear all listboxes for the entire form you can use something like this:
foreach(var listbox in this.Traverse().OfType<ListBox>())
listbox.Items.Clear();
There I use the Traverse helper method to get all of the children, recursively, of a particular control. Here is its implementation:
public static IEnumerable<Control> Traverse(this Control root)
{
var stack = new Stack<Control>();
stack.Push(root);
while (stack.Any())
{
var next = stack.Pop();
foreach (Control children in next.Controls)
stack.Push(children);
yield return next;
}
}
If you don't want to clear all listboxes, but rather only those specified list boxes, then you can try to put all of them into some container, and then traverse that container (rather than the whole form), or if that's not possible you can put them all in a collection and iterate through that collection, i.e.:
ListBox[] listboxes = new[]{
listBox1,
listBox2,
//...
};
foreach(var listbox in listboxes)
listbox.Items.Clear();
If all the controls are in the same form(lets call this form1)
foreach (Control c in form1.Controls)
{
if (c is ListBox)
{
((ListBox)c).Clear();
}
}
If you are finding yourself clearing them over and over in your code and you are wishing to partition the work out, make a method call to cut down on code reuse.
private void ClearList()
{
listBox1.Items.Clear();
listBox2.Items.Clear();
listBox3.Items.Clear();
listBox4.Items.Clear();
listBox5.Items.Clear();
listBox6.Items.Clear();
listBox7.Items.Clear();
listBox8.Items.Clear();
listBox9.Items.Clear();
listBox10.Items.Clear();
}
else, put them into a collection.
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);
}
I have a Form with multiple different controls like ComboBox, TextBox and CheckBox. I am looking for a generic way to get values from these controls while looping over them.
For example, something like this:
foreach(Control control in controls)
{
values.Add(control.Value);
}
Is it possible or do I need to treat each control separately?
Try this:
Panel myPanel = this.Panel1;
List<string> values = new List<string>();
foreach (Control control in myPanel.Controls)
{
values.Add(control.Text);
}
But make sure you get only the controls you want. You can check the type just like
if(control is ComboBox)
{
// Do something
}
The Text solution is OK if every Control is a TextBox, but if you have some Label you'll end up with the text of the labels among the values, unless you fill your code with if's. A better solution could be to define a set of delegates that for each kind of Control return what is considered the value (e.g. Text for the TextBox and Checked for the CheckBox), put them in a dictionary, and use them to get the value for each control. The code could be something like this:
public delegate object GetControlValue(Control aCtrl);
private static Dictionary<Type, GetControlValue> _valDelegates;
public static Dictionary<Type, GetControlValue> ValDelegates
{
get
{
if (_valDelegates == null)
InitializeValDelegates();
return _valDelegates;
}
}
private static void InitializeValDelegates()
{
_valDelegates = new Dictionary<Type, GetControlValue>();
_valDelegates[typeof(TextBox)] = new GetControlValue(delegate(Control aCtrl)
{
return ((TextBox)aCtrl).Text;
});
_valDelegates[typeof(CheckBox)] = new GetControlValue(delegate(Control aCtrl)
{
return ((CheckBox)aCtrl).Checked;
});
// ... other controls
}
public static object GetValue(Control aCtrl)
{
GetControlValue aDel;
if (ValDelegates.TryGetValue(aCtrl.GetType(), out aDel))
return aDel(aCtrl);
else
return null;
}
Then you can write:
foreach (Control aCtrl in Controls)
{
object aVal = GetValue(aCtrl);
if (aVal != null)
values.Add(aVal);
}
the following one doesn't work:
foreach (Control control in Controls) {
if (control is DropDownList) {
DropDownList list = control as DropDownList;
...
}
}
PS: My class extends System.Web.UI.Page
You just need to replace Controls with Form.Controls
foreach (Control c in Form.Controls)
{
if (c is DropDownList)
{
// do something
}
}
Or you can use this extension:
public static IEnumerable<T> AllControls<T>(this Control startingPoint) where T : Control
{
bool hit = startingPoint is T;
if (hit)
{
yield return startingPoint as T;
}
foreach (var child in startingPoint.Controls.Cast<Control>())
{
foreach (var item in AllControls<T>(child))
{
yield return item;
}
}
}
Then you can use it for search of any type of System.Web.UI.Control within specific control. In case of DropDownList you can use it like:
IEnumerable<DropDownList> allDropDowns = this.pnlContainer.AllControls<DropDownList>();
this will find all drop downs within Panel control with ID="pnlContainer".
The problem is that some of the DropDownList controls may be nested in other controls.
If you page has a panel and all of your controls are in that panel the page's control array will only have that panel and all of the control will be in the Panel's control array.
The link that ajax81 linked to will work well.
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...