Code generation using loop - c#

I am new to C# programming. I have number of text boxes on a form and instead of writing the same code for each text box, is it possible to use loop for writing same code for each text box? In the code below can we use the variable i for the same?
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 3; i++)
{
MessageBox.Show(amountTextBox.Text);
MessageBox.Show(amountTextBox1.Text);
MessageBox.Show(amountTextBox2.Text);
MessageBox.Show(amountTextBox3.Text);
}
}
Thanks in advance.

Instead of trying to generate code (which is a lot harder than it sounds), whenever you have variables named something1, something2, … somethingN, you should consider using an array, or some other collection.
Create an array of text boxes, like this:
var amountTextBoxes = new[] { amountTextBox, amountTextBox1, amountTextBox2, amountTextBox3 };
And then loop through them like this:
for (int i = 0; i < amountTextBoxes.Length; i++)
{
MessageBox.Show(amountTextBoxes[i].Text);
}
Or like this:
foreach (var textBox in amountTextBoxes)
{
MessageBox.Show(textBox.Text);
}
Another option that would probably work in this specific case, (though this solution is not as general as the previous one) involves directly searching for the controls based on the name. If this is a Windows Forms application, you could use Find (assuming all controls have the same name pattern):
for (int i = 0; i < 3; i++)
{
var controlName = "amountTextBoxes" + i;
vat textBox = (TextBox)this.Controls.Find(controlName, true)[0];
MessageBox.Show(textBox.Text);
}
Or if this is WPF, you could use FindName:
for (int i = 0; i < 3; i++)
{
var controlName = "amountTextBoxes" + i;
vat textBox = (TextBox)this.FindName(controlName);
MessageBox.Show(textBox.Text);
}

You can try something like this
foreach (Control x in this.Controls)
{
if (x is TextBox)
{
MessageBox.Show(((TextBox)x).Text);
}
}

Better version with OfType extension method:
foreach (TextBox x in this.Controls.OfType<TextBox>().OrderBy(x => x.Name))
{
MessageBox.Show(x.Text);
}

Here is a linq version.
this.Controls
.OfType<TextBox>()
.ToList()
.ForEach(control =>
MessageBox.Show(control.Text));

Instead of using for loop you can do like this also..
*note * - This is for all the textbox controls in the form.. for specific textboxes you may use a for loop which loop through an array or collection of text boxes you need .
foreach(Control control in this.Controls)
{
if(control.GetType() == typeof(TextBox))
{
MessageBox.Show(control.Text);
}
}

As Selman22 mentioned you can solved it using this.Controls.OfType(). You can further refine your query as mentioned below
foreach (TextBox textBox in this.Controls.OfType<TextBox>().Where(x => x.Name.Contains("amountTextBox")).OrderBy(x => x.Name).ToList())
{
MessageBox.Show(textBox.Text);
}

A simple and maintainable way would be to yield return every textbox you're interested in, in the order that you're interested in, and then iterate over that.
private void button1_Click(object sender, EventArgs e)
{
foreach (var textBox in GetAmountTextBoxes())
MessageBox.Show(textBox.Text);
}
private IEnumerable<TextBox> GetAmountTextBoxes()
{
yield return amountTextBox;
yield return amountTextBox1;
yield return amountTextBox2;
yield return amountTextBox3;
}
If you have many textboxes and maintaining this list is cumbersome, you could generalise it to something like:
return Controls.OfType<TextBox>();
But take care to filter it, if necessary, to only the textbox controls you need with Where.
And if order is important, you'll need to devise some function to sort the textboxes (in conjunction with OrderBy). This is necessary because the default sorting algorithm will sort TextBox10 before TextBox1.

Your Code Rewritten:
for (int i = 0; i < 3; i++)
{
MessageBox.Show(amountTextBox[i].Text);
}

Related

How to properly remove all labels from form [duplicate]

Yesterday I wrote a piece of code to remove all the controls in a form that fulfills certain criteria. Writing it naively, this is what I come up with.
for (int i = 0; i < this.Controls.Count; ++i)
{
if (this.Controls[i].Name.Length == 2)
{
this.Controls.Remove(this.Controls[i);
}
}
But it so happens that the code is wrong. I then change it to:
foreach (Control ctr in this.pbBoardImage.Controls)
{
if (ctr.Length == 2)
{
this.Controls.Remove(ctr);
}
}
But it still wasn't correct.
I know that the correct way would be:
for (int i = this.Controls.Count - 1; i >= 0; i--)
{
if (this.Controls[i].Name.Length == 2)
{
this.Controls.Remove(this.Controls[i]);
}
}
However it still doesn't feel elegant. I couldn't use List.RemoveAll, since this.Controls wasn't a List. So can I ask for a more elegant way, preferably without using a loop?
Not sure why you didn't like this answer... I've highlighted the important RemoveAt; however, as an alternative in .NET 3.5/C# 3.0: LINQ:
var qry = from Control control in Controls
where control.Name.Length == 2
select control;
foreach(var control in qry.ToList()) {
Controls.Remove(control);
}
(original)
You can't Remove within foreach - it breaks the iterator. A common approach here is to iterate backwards:
for (int i = this.Controls.Count - 1; i >= 0; i--) {
if (this.Controls[i].Name.Length == 2) {
this.Controls.RemoveAt(i); // <=========== *** RemoveAt
}
}
This avoids the "off by one" issues, etc.

modifying a group of WinForm controls using a loop?

I have a group of textbox controls that i would like to populate with an array of doubles.The controls names are numerically incremented like so
Tol1.Text = lineTolFront[0].ToString();
Tol2.Text = lineTolFront[1].ToString();
Tol3.Text = lineTolFront[2].ToString();
Tol4.Text = lineTolFront[3].ToString();
Tol5.Text = lineTolFront[4].ToString();
Tol6.Text = lineTolFront[5].ToString();
//and so on
is there a simpler way to do this using a loop without having to manually input the values?
First, get all those TextBoxes using LINQ (note: this is useful particularly when you have many controls you do not want manually put in a collection).
var tboxes = this.Controls.Cast<Control>()
.OfType<TextBox>()
.Where(l => l.Name.Contains("Tol"));
and then loop through them and set the content.
int i = 0;
foreach(var tb in tboxes)
tb.Text = lineTolFront[i++].ToString();
You could add the TextBoxes to a collection first. It's a little less copy/paste work at least.
var textBoxes = new List<TextBox> { Tol1, Tol2, Tol3, Tol4, Tol5, Tol6 };
for (var i = 0; i < lineTolFront.Count; i++)
textBoxes[i].Text = lineTolFront[i].ToString();
Regarding M Patel's comment, make sure you add the TextBoxes to the collection in the same order you want to assign the doubles from the lineTolFront array.
You could add your controls to an array and loop through it:
var controls = new[] { Tol1, Tol2, Tol3, Tol4, Tol5, }; //etc
for(int i = 0; i < controls.Length; i++)
{
controls[i].Text = lineTolFront[i].ToString();
}

Convert a PictureBox inside an listBox back into a PictureBox

i have some PictureBoxes in my program with different colors and I want to count, how much boxes there are for one color. So I created a function to count it:
private void cmdCount(object sender, EventArgs e)
{
int counterWhite, counterRed, counterGreen, counterYellow, counterBlue, counterOrange = 0;
if (alreadyAdded == false)
{
lstBox.Items.Add(picA1);
lstBox.Items.Add(picA2);
lstBox.Items.Add(picA3);
//...
alreadyAdded = true;
}
//Log
String value = Convert.ToString(lstBox.Items.Count);
lblLog.Text = "Objects in array: " + value;
for(int i = 0; i < lstBox.Items.Count; i++)
{
if(lstBox.Items[i].BackColor == Color.White)
{
counterWhite += 1;
}
else if...
}
}
I know, that my for-loop will not work that way, but it's the basic idea how I want to do it.
I have put all my PictureBoxes into my list and in the for-loop I want to count them. First it should play as long as the list is long, then every time it goes to the next box and should check the color of it and then add a one to the seperate counters. The problem is that I get errors every time and I have no idea how to read out the values of the BackColors in my list for each item.
Thank you for maybe helping me out :)
You're getting an error because the ListBox.Items collection is an ObjectCollection... it has to be, since it allows you store any object you want in it.
You'll have to cast the object back to a PictureBox before accessing properties on it:
if (((PictureBox)lstBox.Items[i]).BackColor == Color.White)
{
counterWhite += 1;
}
Or you could switch to a foreach loop and cast them all at once (using LINQ):
foreach (var pBox in new lstBox.Items.Cast<PictureBox>())
{
if (pBox.BackColor == Color.White)
{
counterWhite += 1;
}
...
}
Don't use a ListBox control as temporary storage for referencing your PictureBox controls though. You could create a List<PictureBox> to store references in, and then you won't have to cast when you iterate through the collection.
Or better yet (and the one I'd choose), just query the controls on your Form and count the number of controls of type "PictureBox" that have the BackColor you're looking for (using LINQ again).
var counterWhite = Controls.OfType<PictureBox>()
.Count(p => p.BackColor == Color.White);
var counterGreen = Controls.OfType<PictureBox>()
.Count(p => p.BackColor == Color.Green);

how to define an array of textboxes in c#?

Hi when I create textboxes on Windows Application Form I cannot name it as box[0], box[1] and so on. The purpose why I want to do like this is because I want to use them in a loop.
Actually I found TextBox[] array = { firstTextBox, secondTextBox }; works too!
How about making a list of them after you create them? In your form initialization function, you can do something like:
List<TextBox> myTextboxList = new List<TextBox>();
myTextBoxList.Add(TextBox1);
myTextBoxList.Add(TextBox2);
mytextBoxList.Add(TextBox3);
Now you can itterate through with your "myTextboxList" with something like below:
Foreach (TextBox singleItem in myTextboxList) {
// Do something to your textboxes here, for example:
singleItem.Text = "Type in Entry Here";
}
You can create textboxes on runtime and just put them in an array...
If you want to do it in design time, you will have to do some control filtering logic on the whole this.Controls array in order to access only the wanted textboxes. Consider if (currControl is TextBox) if all textboxes in the form are ones you want in the array.
Another option for design time, is putting all wanted textboxes in a panel which will be their parent, and then iterating over the panel's children (controls) and cast them to TextBox.
A runtime solution would be something like:
var arr = new TextBox[10];
for (var i = 0; i < 10; i++)
{
var tbox = new TextBox();
// tbox.Text = i.ToString();
// Other properties sets for tbox
this.Controls.Add(tbox);
arr[i] = tbox;
}
I wouldn't use an array for this, personally. I would use some form of generic collection, like List.
List<TextBox> textBoxList = new List<TextBox>();
//Example insert method
public void InsertTextBox(TextBox tb)
{
textBoxList.Add(tb);
}
//Example contains method
public bool CheckIfTextBoxExists(TextBox tb)
{
if (textBoxList.Contains(tb))
return true;
else
return false;
}
You don't necessarily have to use the Contains method, you could also use Any(), or maybe even find another way- all depends on what you're doing. I just think using a generic collection gives you more flexibility than a simple array in this case.
for C# just use this to create an array of text boxes
public Text [] "YourName" = new Text ["how long you want the array"];
then add the text boxes to the array individually.
TextBox Array using C#
// Declaring array of TextBox
private System.Windows.Forms.TextBox[] txtArray;
private void AddControls(int cNumber)
{
// assign number of controls
txtArray = new System.Windows.Forms.TextBox[cNumber + 1];
for (int i = 0; i < cNumber + 1; i++)
{
// Initialize one variable
txtArray[i] = new System.Windows.Forms.TextBox();
}
}
TextBox[] t = new TextBox[10];
for(int i=0;i<required;i++)
{
t[i]=new TextBox();
this.Controls.Add(t[]);
}

Dynamic Variable Name Use in C# for WinForms

Not sure what is the best way to word this, but I am wondering if a dynamic variable name access can be done in C# (3.5).
Here is the code I am currently looking to "smarten up" or make more elegant with a loop.
private void frmFilter_Load(object sender, EventArgs e)
{
chkCategory1.Text = categories[0];
chkCategory2.Text = categories[1];
chkCategory3.Text = categories[2];
chkCategory4.Text = categories[3];
chkCategory5.Text = categories[4];
chkCategory6.Text = categories[5];
chkCategory7.Text = categories[6];
chkCategory8.Text = categories[7];
chkCategory9.Text = categories[8];
chkCategory10.Text = categories[9];
chkCategory11.Text = categories[10];
chkCategory12.Text = categories[11];
}
Is there a way to do something like ("chkCategory" + i.ToString()).Text?
Yes, you can use
Control c = this.Controls.Find("chkCategory" + i.ToString(), true).Single();
(c as textBox).Text = ...;
Add some errorchecking and wrap it in a nice (extension) method.
Edit: It returns Control[] so either a [0] or a .Single() are needed at the end. Added.
for(...)
{
CheckBox c = this.Controls["chkCategory" + i.ToString()] as CheckBox ;
c.Text = categories[i];
}
You can do that with reflection. But don't.
It's more proper to instantiate a list of contols, add them programmatically to your form, and index that.
Sometimes it can help to put your controls into an array or collection as such:
Checkbox[] chkCataegories = new Checkbox[] { chkCategory1, chkCategory2 ... };
for(int i = 0; i < chkCategories.Length; i++)
chkCategories[i].Text = categories[i];
As another approach, you can dynamically create your checkboxes at runtime instead of design time:
for(int i = 0; i < categories.Length; i++)
{
Checkbox chkCategory = new chkCategory { Text = categories[i] };
someContainer.Controls.Add(chkCategory);
}
At least with dynamically created controls, you don't need to modify your GUI or your form code whenever you add new categories.
You don't need dynamic for that. Put chkCategory1 - 12 in an array, and loop through it with a for loop. I would suggest you keep it around in a field and initialize it at form construction time, because chkCategory seems to be related. But if you want a simple example of how to do it in that simple method, then it would be something like this:
private void frmFilter_Load(object sender, EventArgs e)
{
var chkCategories = new [] { chkCategory1, chkCategory2, chkCategory3, .......... };
for(int i = 0 ; i < chkCategories.Length ; i++ )
chkCategoies[i].Text = categories[i];
}
You know more about the application, so you could perhaps avoid writing out all the control names - for instance, if they are placed on a common parent control, then you could find them by going through it's children.
No, but you could do something like this (untested, beware of syntax errors):
private readonly CheckBox[] allMyCheckboxes = new CheckBox[] { chkCategory1, chkCategory2, ... }
Then you just need to do
for (i = 0; i < 12; i++) allMyCheckboxes[i].Text = categories[i];
The "this.Controls["chkCategory" + i.ToString()]" and "this.Controls.Find("chkCategory" + i.ToString(), true)" both do not work... the former informs you that the contents of the [] are not an int and the latter that ControlCollection does not contain a definition for Find.
Use "Control myControl1 = FindControl("TextBox2");" instead.
I needed this form as I was looping through another array, extracting values and using them to populate form fields. Much easier to look for label1, label2, label3, etc.

Categories