How can I remove all labels where Name starts with "ToClear"?
I tried this code, but it clears them in two clicks (if there are 26 labels it only removes 13 per click)
private void ClearLabel()
{
foreach (var _object in this.Controls)
{
Console.WriteLine(((Label)_object).Name);
if (_object is Label && ((Label)_object).Name.StartsWith("ToClear"))
{
this.Controls.Remove(this.Controls[((Label)_object).Name]);
}
}
}
I wonder that it does not throw an exception. You are enumerating a collection and inside of this loop you are modifying the source. Instead you should collect the controls to remove and then remove them. Easy and readable with LINQ:
var lblRemove = this.Controls.OfType<Label>().Where(l => Name.StartsWith("ToClear")).ToList();
lblRemove.ForEach(this.Controls.Remove);
Note that it will not find nested controls(like your approach). Therefore you have to use a recursive loop, like this: https://stackoverflow.com/a/65855106/284240
The problem was the loop was modifying the collection while still looping over it. That's a no-no. You can do this:
private void ClearLabel()
{
SuspendLayout();
var toRemove = Controls.Where(c => c is Label && c.Name.StartsWith("ToClear")).ToList();
foreach(var control in toRemove)
{
Controls.Remove(control);
}
ResumeLayout();
}
recurse. You can't remove while enumerating. Make a list first, then remove
NOTE: this works for the nested controls
private removeList = new Dictionary<Control, Label>();
private void EnumerateLabels(Control ctrl)
{
foreach (var c in ctrl.Controls)
{
if (c is Label && c.Name.StartsWith("ToClear"))
removeList.Add(ctrl, c);
EnumerateLabels(c); // recurse children
}
}
usage
// assuming `this` is a form
EnumerateLabels(this);
foreach (var kvp in removeList)
kvp.Key.Controls.Remove(kvp.Value);
Disclaimer - not tested
You can do it via RemoveAll:
this.Controls.RemoveAll(c => (c is Label) && c.Name.StartsWith("ToClear"));
See more here: https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.removeall?view=net-6.0
I have 10 text boxes. Like textBox1.Text , textBox2.Text and so on. I need to use textBox2.Text if i=2, textBox2.Text if i =3 and so on.
I did:
string t = "textBox"+i+".Text";
But outcome coming as "textBox1.Text".
How to insert 'i' Value into textBox name instead of 1. And get the outcome as textBox1.Text
So I can use it as name and pass value from textbox to my program.
Based on what I think you are asking, you could store a reference to each TextBox in an array and then use your int to reference it.
TextBox[] boxes = new TextBox[10];
boxes[0] = textBox1;
// ... follow the pattern
boxes[9] = textBox10;
string value = boxes[i-1].Text; // Gets the value of the textBoxi.Text
You can do it like so:
private TextBox GetTB(int i) {
string name = "textBox" + i.ToString();
foreach (var ctrl in Controls) {
var tbox = ctrl as TextBox;
if (tbox?.Name == name) return tbox;
}
return null
}
The easiest way, if you need to access them in C# code this way, would be to maintain an array or List of these textboxes, indexed in order of their numeric value. Then you could simply reference textBoxes[i-1] and get the textbox numbered "i". How you get that array depends on exactly what you're developing. For WinForms, you can use a little Linq on the Form.Controls property:
public static IEnumerable<Control> Flatten(this IEnumerable<Control> controls)
{
var results = new List<Control>();
foreach (var control in controls)
{
results.Add(control);
control.Controls.OfType<Control>().Flatten(results);
}
return results;
}
private static void Flatten(this IEnumerable<Control> controls, List<Control> results)
{
foreach (var control in controls)
{
results.Add(control);
control.Controls.OfType<Control>().Flatten(results);
}
}
...
var textboxes = Form.Controls.Flatten()
.OfType<TextBox>()
.Where(t=>t.Name.StartsWith("textBox"))
.OrderBy(t=>t.Name)
.ToArray();
Here is what I have so far it looks like it will gather the correct amount of selected items from each listbox but instead of outputting the selected ones it outputs the first one over and over.
TabPage page = tabControl1.SelectedTab;
var controls = page.Controls;
foreach (var control in controls)
{
if (control is ListBox)
{
ListBox listbox = control as ListBox;
foreach (var item2 in listbox.SelectedItems)
{
FilterColLB.Items.Add(ShipmentBox.SelectedItem);
}
}
}
Don't reference ShipmentBox.SelectedItem inside the loop:
foreach (var item2 in listbox.SelectedItems)
{
FilterColLB.Items.Add(item2);
}
I would do something more like:
foreach(ListBox lb in tabControl1.SelectedTab.Controls.OfType<ListBox>())
{
foreach(var item in lb.SelectedItems)
{
FilterColLB.Items.Add(item);
}
}
I want to save some selected controls in a list and then compare, i can only select two so it's okay.
Each of the controls have a boolean property Selected, and i need the : Selected == True.
How do i create a method that returns the Selected controls?
Something like:
foreach (Control c in Controls)
{
if ( this.Selected == true )
{
// how to add to a list
}
}
Using LINQ you can do it in one line, this will put all the selected controls into a list and return:
return Controls.Where(c => c.Selected).ToList();
If you want to use foreach just create a list to store controls and populate your list with selected controls:
var selectedControls = new List<Control>();
foreach(var c in Controls)
{
if(c.Selected) selectedControls.Add(c);
}
return selectedControls;
I have a winforms app that has 37 textboxes on the screen. Each one is sequentially numbered:
DateTextBox0
DateTextBox1 ...
DateTextBox37
I am trying to iterate through the text boxes and assign a value to each one:
int month = MonthYearPicker.Value.Month;
int year = MonthYearPicker.Value.Year;
int numberOfDays = DateTime.DaysInMonth(year, month);
m_MonthStartDate = new DateTime(year, month, 1);
m_MonthEndDate = new DateTime(year, month, numberOfDays);
DayOfWeek monthStartDayOfWeek = m_MonthStartDate.DayOfWeek;
int daysOffset = Math.Abs(DayOfWeek.Sunday - monthStartDayOfWeek);
for (int i = 0; i <= (numberOfDays - 1); i++)
{
//Here is where I want to loop through the textboxes and assign values based on the 'i' value
DateTextBox(daysOffset + i) = m_MonthStartDate.AddDays(i).Day.ToString();
}
Let me clarify that these textboxes appear on separate panels (37 of them). So in order for me to loop through using a foreach, I have to loop through the primary controls (the panels), then loop through the controls on the panels. It starts getting complicated.
Any suggestions on how I can assign this value to the textbox?
To get all controls and sub-controls recursively of specified type, use this extension method:
public static IEnumerable<TControl> GetChildControls<TControl>(this Control control) where TControl : Control
{
var children = (control.Controls != null) ? control.Controls.OfType<TControl>() : Enumerable.Empty<TControl>();
return children.SelectMany(c => GetChildControls<TControl>(c)).Concat(children);
}
usage:
var allTextBoxes = this.GetChildControls<TextBox>();
foreach (TextBox tb in allTextBoxes)
{
tb.Text = ...;
}
You Could loop all the controls in the form asking one by one if it is a "Textbox" y ther return the complete List of them.
public List GetTextBoxes(){
var textBoxes = new List();
foreach (Control c in Controls){
if(c is TextBox){
textBoxes.add(c);
}
}
return textBoxes;
}
You can loop through the textboxes in your form in a fairly simple manner:
Func<ControlCollection, List<TextBox>> SearchTextBoxes = null;
SearchTextBoxes = coll => {
List<TextBox> textBoxes = new List<TextBox>();
foreach (Control c in coll) {
TextBox box = c as TextBox;
if (box != null)
textBoxes.Add(box);
if (c.Controls.Count > 0)
textBoxes.AddRange(SearchTextBoxes(c.Controls));
}
return textBoxes;
};
var tbs = SearchTextBoxes(this.Controls).OrderBy(tb => tb.Name);
Edit: Changed according to new requirements. Not nearly as elegant as the LINQ-solution, of course :)
Since this post seems to resurrect itself from time to time and since the solutions above do not find controls inside of controls, such as in a groupbox, this will find them. Just add your control type:
public static IList<T> GetAllControls<T>(Control control) where T : Control
{
var lst = new List<T>();
foreach (Control item in control.Controls)
{
var ctr = item as T;
if (ctr != null)
lst.Add(ctr);
else
lst.AddRange(GetAllControls<T>(item));
}
return lst;
}
And it's use:
var listBoxes = GetAllControls<ListBox>(this);
foreach (ListBox lst in listBoxes)
{
//Do Something
}
Iterate through controls within form and check name of the control if matched then set Text property as you require.
int i = 0;
foreach (Control contrl in this.Controls) {
if (contrl.Name == ("DateTextBox" + i.ToString())) {
contrl.Text = "requiredtexttobeset";
}
i = i + 1;
}
If you want to do without 'foreach' (If you have specific boxes to adjust/address)
int numControls = Page.Form.Controls.Count;
for (int i = 0; i < numControls; i++)
{
if (Page.Form.Controls[i] is TextBox)
{
TextBox currBox = Page.Form.Controls[i] as TextBox;
currbox.Text = currbox.TabIndex.ToString();
}
}
//THE EASY WAY! Always post easy solutions. It's the best way.
//This code is used to loop through all textboxes on a form for data validation.
//If an empty textbox is found, Set the error provider for the appropriate textbox.
foreach (var control in Controls)
{
if (control is TextBox)
{
//Box the control into a textbox. Not really needed, but do it anyway
var textbox = (TextBox)control;
if (String.IsNullOrWhiteSpace(textbox.Text))
{
//Set the errorProvider for data validation
errorProvider1.SetError(textbox, "Data Required!");
textbox.Text = String.Empty; //Clear out the whitespace if necessary
//blnError = true;
}
}
}
You can simply do this mate...
foreach (TextBox txt in this.Panel.Controls.OfType<TextBox>())
{
txt.Text="some value you assign";
}
If your text boxes are on the form directly and not on a Panel then you can replace this.Panel.Controls with this.Controls. That should be short and clear enough for you.
After the InitialiseComponents() call, add the textboxes to a collection member variable on the form. You can then iterate through them in order later on.
You can create a Dictionary of TextBox, int like the following
Dictionary<TextBox, int> textBoxes = new Dictionary<TextBox, int>();
foreach (TextBox control in Controls.OfType<TextBox>())
textBoxes[control] = Convert.ToInt32(control.Name.Substring(11));
Now.. to loop through them..
foreach (var item in textBoxes.Select(p => new { textBox = p.Key, no = p.Value}))
item.textBox.Text = item.no.ToString(); // whatever you want...
Good luck!
Since you already know the name of control, therefore you can search the control by its name.
See Get a Windows Forms control by name in C#
Other answers just not cutting it for you?
I found this as an answer to a similar question on SO, but I can't find the thread now. It recursively loops through ALL controls of a given type which are located within a control. So includes children of children of children of... etc. My example changes the ForeColor of each TextBox to Hot Pink!
public IEnumerable<Control> GetAllControlsOfType(Control control, Type type)
{
var controls = control.Controls.Cast<Control>();
return controls.SelectMany(ctrl => GetAllControlsOfType(ctrl, type))
.Concat(controls)
.Where(c => c.GetType() == type);
}
Implementation:
IEnumerable<Control> allTxtBxs = GetAllControlsOfType(this, typeof(TextBox));
foreach (TextBox txtBx in allTxtBxs)
{
txtBx.ForeColor = Color.HotPink;
}
Quite similar to abatishchev's answer(which, for me, only returned first-level child controls), but different enough to merit it's own answer I think.