I would need some advice or ideas on the problem I'm facing.
I would like to to create a textbox dynamically from an input string like example '11211'.
When it read the first character based on the string above, in this case '1', a textbox with background color yellow would be created.
The loop would continue creating textboxes horizontally till finished reading all the characters in string above.
Snippet of the code is as below :-
foreach (XmlNode xn in list1)
{
string name = xn["BinCode"].InnerText;
disGood.Text = name;
string input = name;
disOccupied.Text = input.Length.ToString();
char[] b = name.ToCharArray();
foreach (char c in b)
{
TextBox[] theTextBoxes = new TextBox[1];
for (int i = 0; i < theTextBoxes.Length; i++)
{
theTextBoxes[i] = new TextBox();
if (c.ToString() == "1")
{
theTextBoxes[i].BackColor = Color.Yellow;
}
}
disGood.Text = c.ToString();
}
}
Some sample or ideas would be high recommended.
Thank you.
I see a lot of redundancies. For example: your array of textboxes is useless, since you always create one textbox during each iteration. The assignment to the extra variable input and b are extra, but unneeded operations. Try this:
foreach (XmlNode xn in list1)
{
string name = xn["BinCode"].InnerText;
disGood.Text = name;
disOccupied.Text = name.Length.ToString();
foreach (char c in name) // You can iterate through a string.
{
TextBox theTextBox = new TextBox();
if (c == '1') // Compare characters.
{
theTextBox.BackColor = Color.Yellow;
}
Controls.Add(theTextBox); // Add the textbox to the controls collection of this parent control.
disGood.Text = c.ToString(); // This will only show the last charachter. Is this as needed?
}
}
To dynamically create and display textbox's horizontally use the below code:
TextBox t = new TextBox()
{
//To display textbox horizontally use the TableLayoutPanel object
TableLayoutPanel(TextBox, Column, Row);
//add any properties specs,
//more property specs,
};
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.
In my firstform, the gridview shows this:
and then i want to parsing to secondform iam using this code
string asscode = gridView1.GetFocusedRowCellValue("AsstCode").ToString();
Assistant assist = new Assistant(asscode);
assist.show();
When parsing, the string is one variable, so i need to split them. I'm using this split to break them
string ass_code;
public Assistant(string z) //this is form 2
{
InitializeComponent();
ass_code = z;
}
in second form i already set a gridview.datasource from another query and so i need to add custom column to the gridview, iam using this code
private void button1_Click(object sender, EventArgs e)
{
string[] names = ass_code.Split(';');
gridView1.BeginUpdate();
DataColumn col = dt.Columns.Add("X", typeof(Boolean));
GridColumn column = gridView1.Columns.AddVisible(col.ColumnName);
column.Caption = col.Caption;
column.Name = col.ColumnName;
gridView1.EndUpdate();
}
for the secondform interface, the gridview display this
what i want to ask is
how do i make the column x got checked base on the asscode so 0110300 and 0110164 and the other value not checked. as you can see on column x it got gray colour which the value is not 1 or 0
when i try to
//string[] names = ass_code.Split(';');
//foreach (string xy in names)
//{
// MessageBox.Show(xy);
//}
it shows that the first was 0110159 but the second string 0110164 got space string on the first character. << because this use for list 1
UPDATE:
well iam using this code but its only check on 0110300 because it set 0110159 back to false
foreach (string x in names)
{
string[] names = ass_code.Split(';');
for (int i = 0; i < gridView1.RowCount; i++)
{
string xg = x.Trim();
string g = gridView1.GetDataRow(i)["code"].ToString().Trim();
if (g == xg)
{
gridView1.SetRowCellValue(i, "Dada", true);
}
else
{
gridView1.SetRowCellValue(i, "Dada", false);
}
}
}
UPDATE2
If leading / trailing spaces is cause of issue then you can do it in two ways:
first way:
string[] names = ass_code.Split(';');
// remove leading / trailing spaces
for (int i = names.Length-1; i >= 0; i-- )
names[i] = names[i].Trim();
second way:
string[] names = ass_code.Split(new char[] { ';', ' '}, StringSplitOptions.RemoveEmptyEntries);
You make to much handy stuff. The Devexpress Grid is really much simpler to use:
var data = //GETYOURDATA
gridControl.DataSource = data;
This populates your data to the grid. You even don't need to create any columns etc. If you want a value now, you shouldn't use GetRowCellValue(); Try to use your DataSource instead.
var actualRow = gridView.GetFocusedRow() as DataRowView;
MessageBox(actualRow["code"]); //Will print your code from code column
What you need to understand is that your DataSource is the source of trues and the GridView just show this data. This becomes more comfortable if you store your data in List<T>.
EXAMPLE:
public class Employee()
{
public int Code{get;set}
public string Name{get;set;}
public bool X {get{return Code == 0110300}}
public static List<Employee> ReadAll(){//Get your data};
}
public class MyForm() : XtraForm
{
var data = Employee.ReadAll();
gridControl.DataSource = data;
//Access Employee code
Employee emp = gridView.GetFocusedRow() as Employee;
MessageBox.Show(emp.Code.ToString());
}
UPDATE
Use the second approach from #Rupesh to remove your spaces. And uses Equals for string comparison. Further set your GridColumn 'X' to column.UnboundType = DevExpress.Data.UnboundColumnType.Bool; to make sure DevExpress don't override your data.
UPDATE-2
var names = ass_code.Split(';').Select(p => p.Trim()).ToList();
for (int i = 0; i < gridView1.RowCount; i++)
{
string g = gridView1.GetDataRow(i)["code"].ToString().Trim();
if (names.Contains(g))
gridView1.SetRowCellValue(i, "Dada", true);
else
gridView1.SetRowCellValue(i, "Dada", false);
}
I'm writing a code where I want to get the numbers from multiple TextBox controls into a collection. Sort it, then change the background color of the textboxes containing the top 3 highest value. This is the dictionary
Dictionary<System.Windows.Forms.TextBox, string> all_cycles = new Dictionary<System.Windows.Forms.TextBox, string>(10);
for (var i = 1; i < 5; i++)
{
all_cycles.Add(((System.Windows.Forms.TextBox)this.Controls.Find("txtendc" + Convert.ToString(i), true)[0]),this.Text);
}
I know that with "this.text" I won't get the textboxes values so that's why I'm asking.
I also tried creating an array which only contains the values of the textboxes which I then use to fill the dictionary. But it always drops an Index was outside the bounds of the array. Or Index was out of range exception. This drops the out of range exception:
List<System.Windows.Forms.TextBox> txtendc = new List<System.Windows.Forms.TextBox>(10);
for (var i = 1; i < 5; i++)
{
txtendc.Add((System.Windows.Forms.TextBox)this.Controls.Find("txtendc" + Convert.ToString(i), true)[0]);
}
int[] endc_content = new int[10];
for (var i = 1;i < 5; i++)
{
endc_content[i]= int.Parse(txtendc[i].Text);
}
I don't have any problem with the coloring, just filling up the dictionary. If you have a better solution than the dictionary collection please tell me.
Thanks
EDIT: This whole code is inside a timer tick event if it matters anything
I would create a list of all of your TextBoxes in code behind when you instantiate your class. Then you could use Linq to get the top 3. Remember that you will need to confirm that all of the textboxes actually contain numbers - ensure that your program doesn't crash if you enter text into one of them. If all of the TextBoxes in the form will be holding these numbers, you could do something like this to validate and sort in one method (not tested):
private List<TextBox> myTextBoxes { get; set; }
public Form1()
{
InitializeComponent();
foreach (Control c in this.Controls)
{
if (c.GetType() == typeof(TextBox))
myTextBoxes.Add((TextBox)c);
}
}
private IEnumerable<TextBox> getTop3()
{
return myTextBoxes.Where(tb => tb.Text.AsEnumerable().All(char.IsDigit)).Select(tb => tb).OrderByDescending(tb => Double.Parse(tb.Text)).Take(3);
}
The first step of the Linq query converts the text to an enumerable of char and ensures that all characters contain digits (instead of letters). The second selects these textboxes. The third parses them into doubles and compares them, highest number first. The last takes the first three in the list (the textboxes containing the highest 3 numbers)
EDIT: Based on your comments, the code could be simplified to:
public Form1()
{
InitializeComponent();
}
private IEnumerable<TextBox> getTop3(string textboxPrefix)
{
List<TextBox> textBoxesToSort = new List<TextBox>();
foreach (Control c in this.Controls)
if (c.GetType() == typeof(TextBox) && c.Name.StartsWith(textboxPrefix))
textBoxesToSort.Add((TextBox)c);
return textBoxesToSort.OrderByDescending(tb => Double.Parse(tb.Text)).Take(3);
}
You can sort those TextBox controls based on values and then select top 3 from the list:
var result = this.Controls.OfType<TextBox>().Select(x =>
{
try { return new { Key = x, Value = Convert.ToInt32(x.Text) }; }
catch { return null; }
})
.Where(x=>x!=null)
.OrderByDescending(x => x.Value)
.Take(3)
.ToDictionary(x => x.Key, x => x.Value);
To test the result, show a message box containing values:
MessageBox.Show(string.Join("\n",
result.Select((x, i) => string.Format("{0}:{1}", i+1, x.Value))));
Above example will be applied on any list of TextBox controls and just for example I used all TextBox controls of the form.
Please try this, hope it helps:
List<System.Windows.Forms.TextBox> all_cycles = new List<System.Windows.Forms.TextBox>(10);
int[] indexOfTextBox = new int[3];
foreach(var cycle in all_cycles)
{
int value = Convert.ToInt16(cycle.Text);
if (value > indexOfTextBox[0])
{
indexOfTextBox[0] = value;
}
else if (value > indexOfTextBox[1])
{
indexOfTextBox[1] = value;
}
else if (value > indexOfTextBox[2])
{
indexOfTextBox[2] = value;
}
}
all_cycles[indexOfTextBox[0]].BackColor = ConsoleColor.Red;
all_cycles[indexOfTextBox[1]].BackColor = ConsoleColor.Blue;
all_cycles[indexOfTextBox[2]].BackColor = ConsoleColor.Green;
How would I go about making a for loop that changes the text in more than 1 textbox?
for (int i; i < 5; i++)
{
textbox(i).text = "something"
}
But I don't know how to get the I to represent the number after the textbox, does anyone know how to?
Store the textboxes in an Array and then loop over the array
for (int i; i < 5; i++)
{
textboxArray[i].text = "something"
}
You could use Controls.Find:
var txts = this.Controls.Find("textbox" + i, true); // true for recursive search
foreach(TextBox txt in txts)
txt.Text = "something";
or - if the TextBoxes are in the same container control(like the Form or a Panel)- with LINQ:
var txts = this.Controls.OfType<TextBox>().Where(txt => txt.Name == "textbox" + i);
foreach(TextBox txt in txts)
txt.Text = "something";
Actually you don't need the loop variable, you could also use String.StartsWith to get all:
var txts = this.Controls.OfType<TextBox>().Where(txt => txt.Name.StartsWith("textbox"));
foreach(TextBox txt in txts)
txt.Text = "something";
if you dont want to alter every textbox on your form just simply add them to a List:
List<TextBox> TextBoxes = new List<TextBox>();
TextBoxes.Add(This.TextBox1);
TextBoxes.Add(This.TextBox3):
then as others have suggested you could either linq or regular foreach the textboxes in the list
TextBoxes.Foreach(Textbox => TextBox.Text = "something");
or
foreach (TextBox r in TextBoxes)
{
r.Text = "something;
}
I need to clear 32 labels on my windows form application, there are other labels present but I do NOT want to clear these. Is there a more efficient and less coded way to do this? My code for this at the moment is as follows using a method: (snippet)
private void ClearFields()
{
label50.Text = string.Empty;
label51.Text = string.Empty;
label52.Text = string.Empty;
label53.Text = string.Empty;
label54.Text = string.Empty;
label55.Text = string.Empty;
// Down to label82
}
I have researched but it's always clearing ALL labels/textboxes.
You could add an object to the Tag of the Label you want to clear.
Label label50 = new Label();
bool deleteMe = true;
label50.Tag = deleteMe;
Then just iterate over your labels and clear all where the Tag is true:
foreach(Label lbl in myLabels)
{
if(lbl.Tag != null && lbl.Tag is bool && (bool)lbl.Tag == true)
{
lbl.Text = String.Empty;
}
}
Try following line:
foreach (Label _label in this.Controls.OfType<Label>().Where(a => a.Name != "Lable32").Select(a => a).ToArray())
_label.Text = string.Empty;
Add non removal lable in where condition if there are many. Here except lable32 all lable text will set to empty.
I would recomend you to place all the labels that need to be cleared in some kind of cointainer. That way you can do something of the sort:
foreach (var child in container.Children)
{
if (child is Label)
{
((Label)child).Text=String.Empty;
}
}
I am not very familiar with WinForms, but I think there are containers there.
Set the Tag property of the labels you do not want cleared to the string "DoNotClear" (using the Property Window or code) then use the following LINQ code:
foreach (var label in Controls.OfType<Label>().Where(l => l.Tag != "DoNotClear"))
label.Text = string.Empty;
Solution : you can use Controls.Find() method to find the controls from id label50 to label82 and assign String.Empty for each identified Label.
Try This:
private void button1_Click(object sender, EventArgs e)
{
for(int i=50;i<83;i++)
{
this.Controls.Find("label" + i,true)[0].Text = String.Empty;
}
}
If all your labels have names like label + id
var labelsToClear = from l in Controls.OfType<Label>()
let id = Int32.Parse(l.Name.Replace("label", ""))
where id >= 50 && id <= 82
select l;
foreach(var label in labelsToClear)
label.Text = String.Empty;
If labels can have different names, then you can filter out labels which match label + id pattern:
Controls.OfType<Label>().Where(l => Regex.IsMatch(l.Name, #"^(?:label)\d+$"))