I have a list that is created from a LINQ to XML query. The list can contain 1, 2, 3 or 4 values. I have four text boxes on the form that should be populated based on the values in the List, but I can't figure out how to do this because the number of elements in the list will vary. Would it be better to dynamically create the textboxes based on the number of values in the list? How could I go about this?
It seems like this would be a fairly common task, but I have not been able to find a solution. Any help would be greatly appreciated.
Creating dynamically, or just populating an existing 4, it doesn't matter. Choose which one is best for your UI requirements. (maybe even a DGV as has been suggested already)
First you need something to contain the controls, lets say you have a panel called MyPanel which will hold only these textboxes and nothing else...
Here's the load dynamically approach:
MyPanel.Controls.Clear();
int count = 1;
foreach(var item in listOfValues)
{
TextBox tb = new TextBox();
tb.Name = "MyTextbox" + i;
tb.Text = item.ToString();//or whatever property you have for the value
tb.Location = new Point(0, 0 + (25 * (i - 1)));
MyPanel.Controls.Add(tb);
}
Here is the fill existing approach, assuming you have 4 TextBoxes called "TextBox1" for example:
int count = 1;
foreach(var item in listOfValues)
{
TextBox tb = MyPanel.Controls.Find("TextBox" + i) as TextBox;
tb.Text = item.ToString();//or whatever property you have for the value
}
NOTE: You need to be sure that listOfItems does not contain more items than you have textboxes for, otherwise you will get an exception
lets say you have a List
List<int> testList = new List<int>(){1,2,3};
foreach(int i in testList)
{
TextBox test = new TextBox();
test1.Name = "textBox"+i;
youcOntrl.Controls.Add(test1);
}
You can also give them their location and size etc.
Sounds like you want to create a foreach loop and iterate round the linq query creating a new text box on each one and adding it to your form. It'd help to see what you've got so far. I've put an example below using a list instead of a linq query but what comes after it is the same
private void Form1_Load(object sender, EventArgs e)
{
var newList= new List<string> {"box1", "box2", "box3"};
foreach (var boxName in newList)
{
TextBox newTextBox = new TextBox();
newTextBox.Text = boxName;
this.Controls.Add(newTextBox);
}
}
You can create 4 text boxes in the forms designer and set their Visible property to be false as default (from the properties pane).
Then, you can switch on the count property of your list as follows:
switch (els.Count)
{
case 1:
textBox1.Text = els[1].Value;
textBox1.Visible = true;
break;
case 2:
textBox1.Text = els[1].Value;
textBox1.Visible = true;
textBox2.Text = els[2].Value;
textBox2.Visible = true;
break;
case 3:
textBox1.Text = els[1].Value;
textBox1.Visible = true;
textBox2.Text = els[2].Value;
textBox2.Visible = true;
textBox3.Text = els[3].Value;
textBox3.Visible = true;
break;
case 4:
textBox1.Text = els[1].Value;
textBox1.Visible = true;
textBox2.Text = els[2].Value;
textBox2.Visible = true;
textBox3.Text = els[3].Value;
textBox3.Visible = true;
textBox4.Text = els[4].Value;
textBox4.Visible = true;
break;
default:
break;
}
If your list is IEnumerable, then you must first call the ToList() method on it to get a List<XElement> as IEnumerable type does not have a Count property.
If it is four or less then you don't have to create dynamically the textboxes. You could probably disable the textbox(es) that could not be populated. And specially if you name your textbox sequentially like TextBox1, TextBox2 etc then you could probably code like:
for (int i = 1; i <= 4; i++)
{
if (i <= list.Count)
{
this.Controls["TextBox"+i.ToString()].Text = list[i-1];
this.Controls["TextBox"+i.ToString()].Enabled = True;
}
else
{
this.Controls["TextBox"+i.ToString()].Enabled = False;
}
}
So, if you have 2 Items in your List for example then List.Count is 2 and therefore Textbox1 and 2 would be populated and TextBox3 and 4 will be disabled.
Related
Visual C#. Looking for a way to iterate through the labels of a TableLayoutPanel to show username and score. The list is sorted by score in descending order.
label1.Text = SortedList[0].Username; label2.Text = Convert.ToString(SortedList[0].Score);
label3.Text = SortedList[1].Username; label4.Text = Convert.ToString(SortedList[1].Score);
label5.Text = SortedList[2].Username; label6.Text = Convert.ToString(SortedList[2].Score);
//Continues until I have 10 rows.
I have written it like this to show that each line is a row. I hope that makes what I am trying to achieve here more clear.
I would do something like this: (sorry it has been awhile since I have done WinForms)
var userNameLabels = Label[10]{label1, label3, label5,....}
var userScocreLabels = Label[10]{label2, label4, label6,....}
for(int i = 0; i <= SortedList.Count(); i++){
userNameLabels[i].Text = SortedList[i].Username;
userScocreLabels[i].Text = SortedList[i].Score.ToString();
}
I think right tool for this job is DataGridView
//below property is true by default - will generate columns for properties automatically
yourDataGridView.AutoGenerateColumns = true;
yourDataGridView.DataSource = SortedList;
I'm new to programming and I'm trying to change the value of a textbox depending of a selected value on a combo box, since the values are numerical 1 to 20, and depending on the selection it will be the number of text boxes visible. I'm using the event selected index changed.
Here is my code:
private void cbxPIN_SelectedIndexChanged(object sender, EventArgs e)
{
int pines = Convert.ToInt32(cbxPIN.SelectedItem.ToString());
if (pines == 1)
{
textbox1.visible = true;
}
else if (pines == 2)
{
textbox1.visible = true;
textbox2.visible = true;
}
...
else if (pines == n)
{
textbox1.visible = true;
textbox2.visible = true;
...
textboxn.visible = true;
}
}
since there are like 25 different numeric values on the combo box is there an easier way of doing this? asides from comparing each different value?
Something like a loop.
At the least, I'd rewrite it like this, to reduce duplication:
private void cbxPIN_SelectedIndexChanged(object sender, EventArgs e)
{
int pines = Convert.ToInt32(cbxPIN.SelectedItem.ToString());
if (pines >= 1)
textbox1.Visible = true;
if (pines >= 2)
textbox2.Visible = true;
...
if (pines >= n)
textboxn.Visible = true;
}
Actually, I'd add all the TextBox controls to a collection, possibly in the constructor:
List<TextBox> TextBoxes = new List<TextBox> { textbox1, textbox2, ... textboxn };
Then use LINQ's Take() method to grab the first xx number of controls and iterate through them:
foreach (var tb in TextBoxes.Take(pines))
textBox.Show();
You want to use a loop structure. You should validate that the number of loops to perform is > 0 and < the number of textboxes you have available, but I'll leave error handling to you.
private void cbxPIN_SelectedIndexChanged(object sender, EventArgs e)
{
int pines = Convert.ToInt32(cbxPIN.SelectedItem.ToString());
TextBox textBox;
for (int i = 1; i <= pines; i++)
{
// get the control from the form's controls collection by the control name
textBox = this.Controls["textbox" + pines.ToString()] As TextBox
textBox.Visible = true;
}
}
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 have a bunch of code that dynamicly creates some controls. It looks in a folder and lists the filenames in it. For each file in the folder it creates a checklistbox item, listbox item and two checkboxes. This is working great and as intended:
private void getAllFiles(string type)
{
try
{
string listPath = "not_defined";
if (type == "internal_mod")
{
int first_line = 76;
int next_line = 0;
int i = 0;
CheckBox[] chkMod = new CheckBox[100];
CheckBox[] chkTool = new CheckBox[100];
listPath = this.internalModsPath.Text;
string[] filesToList = System.IO.Directory.GetFiles(listPath);
foreach (string file in filesToList)
{
if (!internalModsChkList.Items.Contains(file))
{
internalModsChkList.Items.Add(file, false);
string fileName = Path.GetFileName(file);
internalModNameList.Items.Add(fileName);
//-----------------
// Draw Checkboxes
//-----------------
chkMod[i] = new CheckBox(); chkTool[i] = new CheckBox();
chkMod[i].Name = "modChk" + i.ToString(); chkTool[i].Name = "modChk" + i.ToString();
//chkMod[i].TabIndex = i; //chkTool[i].TabIndex = i;
chkMod[i].Anchor = (AnchorStyles.Left | AnchorStyles.Top); chkTool[i].Anchor = (AnchorStyles.Left | AnchorStyles.Top);
chkMod[i].Checked = true; chkTool[i].Checked = false;
chkMod[i].AutoCheck = true; chkTool[i].AutoCheck = true;
chkMod[i].Bounds = new Rectangle(549, first_line + next_line, 15, 15); chkTool[i].Bounds = new Rectangle(606, first_line + next_line, 15, 15);
groupBox7.Controls.Add(chkMod[i]); groupBox7.Controls.Add(chkTool[i]);
//-----------------
next_line += 15;
i++;
}
}
}
Now my problem is that I also want the user to be able to delete all these thing again based on the checklistbox' checked items.. I have no problems deleting the items in the checklistbox or the items in the listbox, but I want to remove the two checkboxes I create too ..
This is what I got to remove the items in the checklistbox, and the listbox
private void internalModListDel_btn_Click(object sender, EventArgs e)
{
int count = internalModsChkList.Items.Count;
for (int index = count; index > 0; index--)
{
if (internalModsChkList.CheckedItems.Contains(internalModsChkList.Items[index - 1]))
{
internalModsChkList.Items.RemoveAt(index - 1);
internalModNameList.Items.RemoveAt(index - 1);
groupBox7.Controls.Remove(modChk[index - 1]);
}
}
}
As you can see I have also tried to write something to remove the checkbox but it doesn't work and I have no idea how to make it work
Can you assist ?
Try using UserControls.
Use the ListBox controller to show those UserControls,
The user control can be built with those checkboxes, and the labels you want .
Another suggestion is to bind this list to an ObservableCollection which will contain the UserContorols you have created.
This way, it will be much more simlpe to add/remove/change the items inside.
I am creating a few checkboxes when I open a form with the following code:
private void OpenFolder_Load(object sender, EventArgs e)
{
int i = 0;
foreach (string file in filesToOpen)
{
Label lbl = new Label();
lbl.Text = Path.GetFileNameWithoutExtension(file);
lbl.Width = 200;
lbl.Height = 25;
lbl.AutoEllipsis = true;
lbl.Location = new System.Drawing.Point(10, 40 + 25 * i);
this.Controls.Add(lbl);
string checkName = "check" + i;
CheckBox check = new CheckBox();
check.Checked = true;
check.AccessibleName = checkName;
check.Location = new System.Drawing.Point(340, 40 + 25 * i);
check.CheckedChanged +=new EventHandler(check_CheckedChanged);
this.Controls.Add(check);
CheckBoxes.Add(check);
i++;
}
and I am trying to check the state of the checkboxes everytime one changes to toggle my OK button (the user can validate only if there are a certain number of the checkboxes checked)
here is the code I use, but it fails as I am not able to target the checkboxes:
private void check_CheckedChanged(Object sender, EventArgs e)
{
for (int i = 0; i < filesToOpen.Count(); i++)
{
string tbarName = "tbar" + i;
string checkName = "check" + i;
CheckBox ckb = this.Controls.OfType<CheckBox>()
.Where(c => c.AccessibleName.Equals(checkName)) as CheckBox;
TrackBar tkb = this.Controls.OfType<TrackBar>()
.Where(t => t.AccessibleName.Equals(tbarName)) as TrackBar;
//TrackBar tkb = this.Controls.Find(tbarName, false).First() as TrackBar;
//CheckBox ckb = this.Controls.Find(checkName, false).First() as CheckBox;
if (ckb.Checked == true)
{
//do stuff
}
}
}
what am I doing wrong/really wrong?
Given that you add the checkboxes to your own list:
CheckBoxes.Add(check);
it would be simpler to loop over that rather than trying to find the control associated with the file:
foreach (var checkBox in CheckBoxes)
{
if (checkbox.Checked)
{
// Do stuff...
}
}
However, you shouldn't need to use a separate list. This line is wrong:
CheckBox ckb = this.Controls.OfType<CheckBox>()
.Where(c => c.AccessibleName.Equals(checkName)) as CheckBox;
Where returns a IEnumerable<CheckBox> but you are trying to cast it directly to a CheckBox which will return null. What you should have is:
CheckBox ckb = this.Controls.OfType<CheckBox>()
.Where(c => c.AccessibleName.Equals(checkName)).First();
You will still need to check to see if ckb is null (just in case there is nothing on the list) but this should return you the control you are looking for.
Check the type of "this" and then check its Controls collection - your checkboxes are probably a few iterations down the tree.
You'd need some kind of recursive find controls function such as the one found in this article
Iterating over all the checkboxes with every check is not required and is readlly hard processing work. Instead when creating you always know in what state you've created those - so just keep the count of "Checked" checkboxes. When a checkbox being checked increment the count, and when one unchecked - take out 1 from the count. And later have a check: "if (count == requiredCount) {//Logic here}"
So the code will look like:
private int checkedCount;
private void check_CheckedChanged(Object sender, EventArgs e)
{
this.checkedCount += (sender as CheckBox).Checked?1:-1;
if(this.checkedCount == requiredCount)
{
//do stuff
}
}
Good luck with development.