I want to create 32 labels in my Form so I used code like this:
//using System.Windows.Forms;
Label[] Lb_clubs;
Lb_clubs = new Label[32];
foreach(Label lb in Lb_clubs)
{
lb = new Label();
lb.Text = "somename";
//and other codes
}
But I am getting an error
CS1656 : Cannot assign lb because it is a foreach iteration variable.
Any Solution?
You can use a for loop as described by the #Phils and #rickvdbosch, but you can keep you foreach loop by using Enumerable.Select:
//using System.Windows.Forms;
Label[] Lb_clubs;
Lb_clubs = new Label[32].Select(lbl => new Label()).ToArray();
foreach (Label lb in Lb_clubs)
{
lb.Text = "somename";
//and other codes
}
You can't assign to the lb variable, because it's a foreach iteration variable, so it's in a read-only context. That's why you're getting Compiler Error CS1656:
This error occurs when an assignment to variable occurs in a read-only context. Read-only contexts include foreach iteration variables, using variables, and fixed variables. To resolve this error, avoid assignments to a statement variable in using blocks, foreach statements, and fixed statements.
Try a for-loop:
Label[] Lb_clubs;
Lb_clubs = new Label[32];
for (int i = 0; i < 32; i++)
{
var lb = new Label();
lb.Text = "somename";
//and other codes
Lb_clubs[i] = lb;
}
You need to use a for loop, not foreach
Label[] Lb_clubs;
Lb_clubs = new Label[32];
for (int i = 0; i < 32; i++)
{
var lb = new Label();
lb.Text = "somename";
//and other codes
Lb_clubs[i] = lb;
}
You can't assign a value in a foreach loop: you should also see the lb = new Label(); marked in the editor, which should tell you that it
Cannot assign to 'lb' because it is a 'foreach iteration variable'
which generates a Compiler Error CS1656.
You can do this (besides what others have already suggested) in one line, using Enumerable.Range:
var Lb_clubs = Enumerable.Range(0, 32).Select(l => new Label() { Text = "SomeText" }).ToArray();
Slightly different, adding a progressive value to the text, using the index of the enumeration and also assign a Name (and/or other values) to the Label, if needed:
var Lb_clubs = Enumerable.Range(0, 32).Select(idx => new Label() {
Text = "SomeText" + idx.ToString(),
Name = "SomeName" + idx.ToString() }).ToArray();
Related
Target:
To write in the label text, but the label ID is assigned by a string.
Problem:
It doesn't work, no errors given. I looked in most places for an answer but nothing helped!
My Code:
string asdfj = treeView2.SelectedNode.Text;
string adqien = System.IO.Path.Combine(dir7, asdfj);
string[] tnsop = System.IO.File.ReadAllLines(#adqien);
h1a.Text = "100";
for (int o = 2; o > 6; o++)
{
//This is the label name e.g "h2a',h3a" etc
string tempc = string.Format("h" + o.ToString() + "a");
foreach (Control ctr in this.Controls)
{
if (ctr is Label)
{
if (ctr.Name == tempc)
{
ctr.Text = tnsop[o];
}
}
}
}
I also consulted this post:
Use string variable content as label ID to update label.Text, I get error - 'string' does not contain a definition for 'Text'
You can do it simply like:
this.Controls.Find(labelname).Text = Value;
or
this.Controls.OfType<Label>().FirstOrDefault(x => x.Name == labelName).Text = Value;
The for loop
First of all, this is wrong for (int o = 2; o > 6; o++).
It starts at o = 2, then checks if o > 6, which is false, because o = 2, and then skips the loop.
I guess you wanted to write: for (int o = 2; o < 6; o++). I am not sure about that, fix it as appropiate.
Addendum: This would have been easily discovored by debugging and stepping. You can start by adding a break point on your code (in Visual Studio you can place your cursor on the desired line and press F9 - by default) and then run in the debugger. When the a line with the break point is reached, the debbuger stops the execution and let you inspect the values of the variables, the call stack, etc. You can then step with F10 or F11 (if you want to inside a method call) and see how the code evolves. You would notice it does not enter the for loop.
Finding the labels
If finding the label still does not work, I would guess the problem is that the labels are not directly on the form or that they do not have the given name.
You can use this.Controls.Find(name, searchAllChildren) to get the labels you need.
That is:
string labelName = string.Format("h" + o.ToString() + "a");
Control[] control = this.Controls.Find(labelName, true);
Note: Yes, I can figure out it is the name of the label by how you use it. Using a comment to tell me saves some time... however, please use better variable names. You won't need a comment to tell me this is the name of the label if the variable name says so.
You still need to check it for the label:
string labelName = string.Format("h" + o.ToString() + "a");
Control[] controls = this.Controls.Find(labelName, true);
foreach (Control control in controls)
{
if (control is Label) // if (control.GetType() == typeof(Label))
{
// ...
}
}
Building a Dictionary
However, I would advice against doing this every time. Instead, I suggest to build a dictionary:
Dictionary<string, Label> labels;
// ...
labels = new Dictionary<string, Label>();
for(int o = 2; o < 6; o++)
{
string labelName = string.Format("h" + o.ToString() + "a");
Label label = GetLabel(labelName);
labels.Add(labelName, label);
}
// ...
private Label GetLabel(string labelName)
{
Control[] controls = this.Controls.Find(labelName, true);
foreach (Control control in controls)
{
if (control is Label) // if (control.GetType() == typeof(Label))
{
return control as Label;
}
}
return null;
}
Note: I suggest to make the dictionary a field and initialize it only once during the form load.
This separates the responsability of finding the labels from reading the file (which is external to the program). Allowing you to test if it can find the right controls without the need of a file.
It will also make the case where the Label is not found visible (we just added a null to the dictionary).
And then use it:
string[] tnsop = System.IO.File.ReadAllLines(#adqien);
for (int o = 2; o < 6; o++)
{
string labelName = string.Format("h" + o.ToString() + "a");
label = labels[labelName];
label.Text = tnsop[o];
}
The code above should throw NullReferenceException if the label was not found while building the dictionary.
Simplify
I guess we can do better. The designer will create fields for your labels, you can just add them to the dictionary:
Dictionary<string, Label> labels;
// ...
labels = new Dictionary<string, Label>();
labels["h2a"] = h2a;
labels["h3a"] = h3a;
labels["h4a"] = h4a;
labels["h5a"] = h5a;
// ...
string[] tnsop = System.IO.File.ReadAllLines(#adqien);
for (int o = 2; o < 6; o++)
{
string labelName = string.Format("h" + o.ToString() + "a");
label = labels[labelName];
label.Text = tnsop[o];
}
Note: There are plenty of opportunities for more modern syntax, including collection initialization and the var keyword.
Addendum: I am unrolling the loop in the above code, this is ok for maintainability if the number of iterations small, in fact, it is a common optimization. You could, in theory do it for the other loop too.
PS. An array will do
I noticed, after finishing writing, that the code only needs to look up by an int o.
We can rework to use int for dictionary keys:
Dictionary<int, Label> labels;
// ...
labels = new Dictionary<int, Label>();
labels[2] = h2a;
labels[3] = h3a;
labels[4] = h4a;
labels[5] = h5a;
// ...
string[] tnsop = System.IO.File.ReadAllLines(#adqien);
for (int o = 2; o < 6; o++)
{
label = labels[o];
label.Text = tnsop[o];
}
Now we have less concatenations, and a simpler code.
We could, in fact, be using an array:
Label[] labels;
// ...
labels = new Label[4];
labels[0] = h2a;
labels[1] = h3a;
labels[2] = h4a;
labels[3] = h5a;
// ...
string[] tnsop = System.IO.File.ReadAllLines(#adqien);
for (int o = 2; o < 6; o++)
{
label = labels[o - 2];
label.Text = tnsop[o];
}
Notice I did offset the indexes to be able to use the array from index 0.
I made 10 Labels dynamically.
Now, I'd like to delete them with the same way (dynamically).
What do I have to do ?
Thanks..
for( int i = 1 ; i < 11 ; i++ )
{
var myLabel = new System.Windows.Forms.Label();
myLabel.Text = "dynaLabel_" + i.ToString();
myLabel.Location = new System.Drawing.Point(200, i * 23);
Controls.Add(myLabel);
Application.DoEvents();
Thread.Sleep(199);
}
Just a simple for loop in which you should find out label, remove it from Controls and release allocated resources:
// let's use regular expression to validate name;
// String.StartsWith is also a good choice
using System.Text.RegularExpressions;
...
// while removing, loop backward
for (int i = Controls.Count - 1; i >= 0; --i) {
Label label = Controls[i] as Label;
// Control is Label with specific name
if ((label != null) && Regex.IsMatch(label.Text, "^dynaLabel_[0-9]+$")) {
Controls.RemoveAt(i);
// do not forget to release resources allocated (here is HWND - window handle)
label.Dispose();
}
}
So is this your homework?
using System.Linq;
...
foreach(Control c in Controls.OfType<Label>().ToList())
{
//check if correct label if you need to
Controls.Remove(c);
}
You could use Controls and LINQ Where to do the job:
var labels = Controls.Cast<Control>()
.Where(c => c is Label && c.Text.StartsWith("dynaLabel_"));
foreach (var label in labels){
Controls.Remove(label);
label.Dispose();
}
Since you create the labels as Label and having the Text starting with value of dynaLabel_, your LINQ should also find those specific labels. Thus, you use both c is Label and StartsWith("dynaLabel_") there.
So I have this kind of code (I'm assigning values to XAML elements
), which begs for a "for" loop.
Day1d.Text = string.Format("{0:dd/MM}", DateTime.Today.AddDays(1));
Day2d.Text = string.Format("{0:dd/MM}", DateTime.Today.AddDays(2));
Day3d.Text = string.Format("{0:dd/MM}", DateTime.Today.AddDays(3));
Day4d.Text = string.Format("{0:dd/MM}", DateTime.Today.AddDays(4));
Day1t.Text = "°" + (myWeatherForecast.forecastlist[1].temp).ToString();
Day2t.Text = "°" + (myWeatherForecast.forecastlist[2].temp).ToString();
Day3t.Text = "°" + (myWeatherForecast.forecastlist[3].temp).ToString();
Day4t.Text = "°" + (myWeatherForecast.forecastlist[4].temp).ToString();
But all my attempts to include "i" in variable name failed miserably. Is there a way to achieve this?
You can create a loop where you iterate over the instances:
int counter = 1; // are you sure it shouldn't start at 0?
foreach (TextBox tb in new TextBox[] { Day1d, Day2d, Day3d, Day4d })
{
tb.Text = string.Format("{0:dd/MM}", DateTime.Today.AddDays(counter));
counter++;
}
counter = 1;
foreach (TextBox tb in new TextBox[] { Day1t, Day2t, Day3t, Day4t })
{
tb.Text = "°" + (myWeatherForecast.forecastlist[counter].temp).ToString();
counter++;
}
You can't compose the name of the variable using another variable. The way to do this would be to create a List and then iterate over that List
var textBoxes1 = new List<TextBox> { Day1d, Day2d, Day3d, Day4d }
var textBoxes2 = new List<TextBox> { Day1t, Day2t, Day3t, Day4t }
foreach (var textbox in textBoxes1)
{
var index = textBoxes1.IndexOf(textBox) + 1;
textbox.Text = string.Format("{0:dd/MM}", DateTime.Today.AddDays(index));
}
foreach (var textbox in textBoxes2)
{
var index = textBoxes2.IndexOf(textBox) + 1;
textbox.Text = "°" + (myWeatherForecast.forecastlist[index].temp).ToString();
}
NOTE: You can solve this in different ways:
using arrays instead of lists
keeping your own counter, instead of doing IndexOf
using a for loop, instead of a foreach
Which one is better is mostly based on opinion (although my method is not the fastest, but it doesn't matter if you only have 4 items)
You can use FindName assuming you are using WPF.
Try:
for (int i = 1; i < 5; i++)
{
((TextBox)this.FindName("Day" + i + "d")).Text = string.Format("{0:dd/MM}", DateTime.Today.AddDays(i));
((TextBox)this.FindName("Day" + i + "t")).Text = "°" + (myWeatherForecast.forecastlist[i].temp).ToString();
}
Suppose I have this in page load:
Label lblc = new Label();
for (int i = 1; i <= 10; i++)
{
lblc.Text = i.ToString();
this.Controls.Add(lblc);
}
How can I manipulate each of these controls at run time?
I want to:
Set/get their text.
Reference a particular control, in this case Label.
Use an array if you know how many labels you will have,
Label[] lblc = new Label[10];
for (int i = 0; i < 10; i++)
{
lblc[i] = new Label() { Text = (i + 1).ToString() };
this.Controls.Add(lblc[i]);
}
Then you will reference the textbox 1 with lblc[0] and textbox 2 with lblc[1] and so on. Alternatively if you do not know how many labels you will have you can always use something like this.
List<Label> lblc = new List<Label>();
for (int i = 0; i < 10; i++)
{
lblc.Add(new Label() { Text = (i + 1).ToString() });
this.Controls.Add(lblc[i]);
}
You reference it the same way as the array just make sure you declare the List or the array outside your method so you have scope throughout your program.
Suppose you want to do TextBoxes as well as Labels well then to track all your controls you can do it through the same list, take this example where each Label has its own pet TextBox
List<Control> controlList = new List<Control>();
for (int i = 0; i < 10; i++)
{
control.Add(new Label() { Text = control.Count.ToString() });
this.Controls.Add(control[control.Count - 1]);
control.Add(new TextBox() { Text = control.Count.ToString() });
this.Controls.Add(control[control.Count - 1]);
}
Good luck! Anything else that needs to be added just ask.
Your code creates only one control. Because, label object creation is in outside the loop. you can use like follows,
for (int i = 1; i <= 10; i++)
{
Label lblc = new Label();
lblc.Text = i.ToString();
lblc.Name = "Test" + i.ToString(); //Name used to differentiate the control from others.
this.Controls.Add(lblc);
}
//To Enumerate added controls
foreach(Label lbl in this.Controls.OfType<Label>())
{
.....
.....
}
Better to set the Name and then use that to distinguese between the controls
for (int i = 1; i <= 10; i++)
{
Label lblc = new Label();
lblc.Name = "lbl_"+i.ToString();
lblc.Text = i.ToString();
this.Controls.Add(lblc);
}
when:
public void SetTextOnControlName(string name, string newText)
{
var ctrl = Controls.First(c => c.Name == name);
ctrl.Text = newTExt;
}
Usage:
SetTextOnControlName("lbl_2", "yeah :D new text is awsome");
i got this GetEnumerator problem.. here's my situation
Panel eachPanel = new Panel();
eachPanel.Size = new Size(pnlProcessCon.Width - 27, 24);
eachPanel.Location = new Point(5, startPoint);
eachPanel.BackColor = (defaultColor == alterColor[0]) ? alterColor[1] : alterColor[0];
TextBox txtProcess = new TextBox();
txtProcess.Size = new Size(50, 20);
txtProcess.Location = new Point(2,2);
txtProcess.TextAlign = HorizontalAlignment.Center;
txtProcess.Text = "P" + Convert.ToString(startProcess);
TextBox txtBurstTime = new TextBox();
txtBurstTime.Size = new Size(50, 20);
txtBurstTime.Location = new Point(txtProcess.Right + 70, 2);
txtBurstTime.TextAlign = HorizontalAlignment.Center;
TextBox txtPriority = new TextBox();
txtPriority.Size = new Size(50, 20);
txtPriority.Location = new Point(txtBurstTime.Right + 70, 2);
txtPriority.TextAlign = HorizontalAlignment.Center;
eachPanel.Controls.Add(txtProcess);
eachPanel.Controls.Add(txtBurstTime);
eachPanel.Controls.Add(txtPriority);
pnlProcessCon.Controls.Add(eachPanel);
but when i call each of their text and add to dictionary, i got this error..
Error 1 foreach statement cannot operate on variables of type 'System.Windows.Forms.Panel' because 'System.Windows.Forms.Panel' does not contain a public definition for 'GetEnumerator' C:\Users\vrynxzent#yahoo.com\Documents\Visual Studio 2008\Projects\Scheduler\Scheduler\Form1.cs 68 13 Scheduler
and got my error here..
foreach (var each in pnlProcessCon)
{
String[] temp = new String[3];
foreach (var process in each)
{
temp = process.Text;
}
}
There are a few issues there.
First, you should enumerate the Controls collections. Second, you will have to cast each control to TextBox before you can retrieve the text. Third, you declared temp as an array, so you can't directly assign a string to it. Fourth (as Henk Holterman pointed out), you should use actual types and not var in the foreach loops.
I'm going to take a stab at working code here. Feel free to adjust for your own needs.
TextBox txtProcess = new TextBox();
txtProcess.Name = "Process";
//configure other textboxes, add to panels, etc.
foreach (Panel each in pnlProcessCon.Controls)
{
String[] temp = new String[3];
foreach (Control control in each.Controls)
{
if(control.Name == "Process")
{
temp[0] = ((TextBox)control).Text;
}
}
}
This would be the general idea (note: no var)
foreach (Panel p in pnlProcessCon.Controls)
{
foreach (Control process in p.Controls)
{
}
}
But make sure pnlProcessCon only contains Panels.