I create TextBoxes dynamically, one for each column in a table(DataGridView). Every time I select a row in Table a text Box should have the value of the primaryKey row. First time it works, but after that the TextBox Text is not changing. But if I put a MessageBox to print the textbox.Text it printed it right, but not displayed it. When I tried the same thing with textboxes that aren't created dynamically I didn't have this problem.
for (int i = 0; i < columns_number; i++)
{
textBoxes[i] = new TextBox();
labels[i] = new Label();
labels[i].Text = childTable.Columns[i].Name;
labels[i].Location = new Point(x_point - 100, y_point);
textBoxes[i].Location = new Point(x_point, y_point);
this.Controls.Add(labels[i]);
this.Controls.Add(textBoxes[i]);
y_point = y_point + 30;
}
textBoxes[number].Text = selectedRow.Cells[vaterPrimaryKey].Value.ToString();
textBoxes[number].Refresh();
Use the below code to find the textboxs and use them the way you want :
string textboxName = "textboxes" + number.ToString
TextBox mytextbox = this.Controls.Find(textboxName, true).FirstOrDefault() as TextBox;
mytextbox.Text = selectedRow.Cells[vaterPrimaryKey].Value.ToString();
Related
I have a Windows form on which I put a flow layout panel. I also have a class that reads a local database and returns the corresponding values. Depending on the user input via a button(s) the panel gets filled with other buttons. The amount of these buttons depends on the values in the local database. The buttons are displayed correctly and with the correct information, but the order in which they are displayed is alphabetical even though the data-table, from the database class, is ordered in the correct way (via the numerical value of the "ID" column from the database).
I have also added a data-grid view to check and there the items are displayed in the correct way. I have tried to add a for-each loop but that just seems to randomize the order of the buttons.
Does anybody know how I can get the buttons to be displayed in the correct way, so that the button with the lowest "ID" value gets displayed first.
Here is the code for displaying the buttons:
//set the datagridview with the correct values/names. Order works perfectly
dataGridView_AttackName.DataSource = db.attackIDName(attackCategory, taughtOn);
DataTable dt = db.attackIDName(attackCategory, taughtOn);
//sort datable again because doesnt work from db class
dt.DefaultView.Sort = "ID";
dt.DefaultView.ToTable();
int horizontal = 0;
int vertical = 0;
Button[] buttonArray = new Button[dt.Rows.Count];
for (int items = 0; items < buttonArray.Length; items++)
{
buttonArray[items] = new Button();
buttonArray[items].Size = new Size(150, 50);
buttonArray[items].Location = new Point(horizontal, vertical);
buttonArray[items].Name = string.Format("Button_{0}", dt.Rows[items]["ID"].ToString());
buttonArray[items].Text = dt.Rows[items]["Name"].ToString();
buttonArray[items].Click += btn_msg;
if ((items + 1) < buttonArray.Length)
{
vertical += 50;
}
flowLayoutPanel_AttackName.Controls.Add(buttonArray[items]);
}
//get the correct ID value from the button name and try to order it that way
foreach (Button b in flowLayoutPanel_AttackName.Controls)
{
string name = b.Name;
string subname = name.Substring(name.IndexOf("_") + 1);
int i = Convert.ToInt32(subname);
flowLayoutPanel_AttackName.Controls.SetChildIndex(b, i);
}
I have searched around on this site but couldn't find anything that worked.
You've correctly sorted the DefaultView by the ID, but then haven't used the results!
You need to replace, for example, dt.Rows[items]["Name"]with dt.DefaultView[items].Row["Name"]. You then don't need the statement dt.DefaultView.ToTable().
Full code is below:
dt.DefaultView.Sort = "ID";
int horizontal = 0;
int vertical = 0;
Button[] buttonArray = new Button[dt.Rows.Count];
for (int items = 0; items < buttonArray.Length; items++)
{
buttonArray[items] = new Button();
buttonArray[items].Size = new Size(150, 50);
buttonArray[items].Location = new Point(horizontal, vertical);
buttonArray[items].Name = string.Format("Button_{0}", dt.DefaultView[items].Row["ID"].ToString());
buttonArray[items].Text = dt.DefaultView[items].Row["Name"].ToString();
buttonArray[items].Click += btn_msg;
if ((items + 1) < buttonArray.Length)
{
vertical += 50;
}
flowLayoutPanel_AttackName.Controls.Add(buttonArray[items]);
}
I am creating an application where different kinds of survey questions are pulled from a database.
The first kind I am implementing is a list of questions each with four radio buttons to choose from.
My code for creating the radio button lists and mark up dynamically is
protected void ProcessData(DataTable question, DataTable answers)
{
int i = 0;
foreach (DataRow row in question.Rows)
{
HtmlGenericControl rowDiv = new HtmlGenericControl("div");
rowDiv.Attributes["class"] = "classRowDiv";
panel1.Controls.Add(rowDiv);
HtmlGenericControl questionDiv = new HtmlGenericControl("div");
questionDiv.Attributes["class"] = "classQuestionDiv";
questionDiv.ID = "questionDiv" + i.ToString();
rowDiv.Controls.Add(questionDiv);
Label questionLabel = new Label();
questionLabel.Attributes["class"] = "classQuestionLabelDiv";
if (row[2].ToString() == "Radio button")
{
questionLabel.Text = row[3].ToString();
rowDiv.Controls.Add(questionLabel);
HtmlGenericControl radioDiv = new HtmlGenericControl("div");
radioDiv.Attributes["class"] = "classRadioDiv";
radioDiv.ID = "radioDiv" + i.ToString();
rowDiv.Controls.Add(radioDiv);
RadioButtonList rbl = new RadioButtonList();
rbl.ID = "List" + i.ToString();
radioDiv.Controls.Add(rbl);
rbl.RepeatDirection = RepeatDirection.Horizontal;
Label lbl = new Label();
lbl.Text = "<hr />";
panel1.Controls.Add(lbl);
DataRow rowA;
for (int j = 0; j < 4; j++ )
{
rowA = answers.Rows[j];
ListItem button = new ListItem(rowA[2].ToString(), j.ToString());
button.Attributes["class"] = "radioStyle";
rbl.Items.Add(button);
}
i++;
}
}
}
The problem I am having is actually getting the selected values of the buttons. I have come to understand from reading around that dynamically created controls must be re-loaded with the same ID after a postback but I do not fully understand how to achieve this as the amount of radio buttons created is dependent on the result set from the database.
I'm trying to populate a Flow Layout Panel with ComboBoxes and NumbericUpDowns.
The problem I'm having is using both the new NumbericUpDowns with the new ComboBoxes. Here is how I'm generating the ComboBoxes and NumericUpDowns.
// This int increments each time the code is run. It's located outside of the method below.
int captchaID = 0;
.
// Textboxes that are only for the UI, no code interaction based on text input.
string textboxText = "captchaTextbox";
TextBox newTextbox = new TextBox();
newTextbox.Name = captchaID.ToString() + textboxText;
newTextbox.Text = "";
newTextbox.Width = 175;
itemFlowPanel.Controls.Add(newTextbox);
// Combo Boxes
string comboBoxText = "captchaComboBox";
ComboBox newComboBox = new ComboBox();
newComboBox.Name = captchaID.ToString() + comboBoxText;
newComboBox.Width = 50;
newComboBox.DropDownStyle = ComboBoxStyle.DropDownList;
itemFlowPanel.Controls.Add(newComboBox);
// This array holds my strings that are added to each ComboBox
string[] skills = new string[6];
skills[0] = "STR";
skills[1] = "DEX";
skills[2] = "CON";
skills[3] = "INT";
skills[4] = "WIS";
skills[5] = "CHA";
// This for loop is just populating my ComboBox with the array.
for (int i = 0; i < skills.Length; i++)
{
newComboBox.Items.Add(skills[i]);
}
// Numeric Up Downs
string numericUpDownText = "captchaNumericUpDown";
NumericUpDown newNumericUpDown = new NumericUpDown();
newNumericUpDown.Name = captchaID.ToString() + numericUpDownText;
newNumericUpDown.Width = 50;
newNumericUpDown.ValueChanged += new EventHandler(captchaNumericUpDown_Click);
newNumericUpDown.ValueChanged += new EventHandler(captchaNumericUpDown_ValueChanged);
itemFlowPanel.Controls.Add(newNumericUpDown);
captchaID++;
With the current code, I'm able to edit an EventHandler that each NumericUpDown contains, but I haven't found a way to make it able to read it's corresponding combobox (which increment together with captchaID).
What I'd like to be able to do, is create a new unique event for each, but if that's not possible, a way to check the ID of the combobox would help as well.
Here are quick solutions:
1) By using dictionary
Dictionary<NumericUpDown, ComboBox> _controls = new Dictionary<NumericUpDown, ComboBox>();
// when you create comboBox - add entry with associated numericUpDown
_controls.Add(numericUpDown1, comboBox1);
// now in the numericUpDown event you can get combobox like this
void numericUpDown_Whatever(object sender, WhateverEventArgs e)
{
var numericUpDown = (NumericUpDown)sender;
var comboBox = _controls[numericUpDown];
// do something
var selectedIndex = comboBox.SelectedIndex;
...
}
2) By using Tag
// add combobox into numericUpDown Tag when you create them
numericUpDown1.Tag = comboBox1;
// now in the numericUpDown event you can get combobox like this
void numericUpDown_Whatever(object sender, WhateverEventArgs e)
{
var numericUpDown = (NumericUpDown)sender;
var comboBox = (CombBox)numericUpDown.Tag;
// do something
var selectedIndex = comboBox.SelectedIndex;
...
}
You can rewrite your captchaNumericUpDown_ events to take a ComboBox as an additional parameter and then call them like this:
newNumericUpDown.ValueChanged += (sender, args) =>
{
captchaNumericUpDown_Click(sender, args, newComboBox);
}
I am dynamically creating several HtmlTableRows and adding cells to them, like so:
HtmlTable dynamicTable = new HtmlTable();
. . .
// Create row 6
var row6 = new HtmlTableRow();
var cellLitCtrl_6 = new HtmlTableCell();
var cellTxtbx_6 = new HtmlTableCell();
row6.Cells.Add(cellLitCtrl_6);
row6.Cells.Add(cellTxtbx_6);
var mailStopStr = new Label
{
CssClass = "dplatypus-webform-field-label",
Text = "Mail Stop:"
};
cellLitCtrl_6.Controls.Add(mailStopStr);
boxMailStop = new TextBox
{
CssClass = "dplatypus-webform-field-input"
};
cellTxtbx_6.Controls.Add(boxMailStop);
dynamicTable.Rows.Add(row6);
// Create row 7
var row7 = new HtmlTableRow();
var cellCkbx_7 = new HtmlTableCell();
var cellLitCtrl_7 = new HtmlTableCell();
var cellTxtbx_7 = new HtmlTableCell();
row7.Cells.Add(cellCkbx_7);
row7.Cells.Add(cellLitCtrl_7);
row7.Cells.Add(cellTxtbx_7);
CheckBox ckbxEmployeeQ = new CheckBox
{
CssClass = "dplatypus-webform-field-input",
ID = "ckbxEmp",
};
ckbxEmployeeQ.Text = "Employee?";
cellCkbx_7.Controls.Add(ckbxEmployeeQ);
var SSNOrITINStr = new Label
{
CssClass = "dplatypus-webform-field-label",
Text = "ITIN:",
ID = "lblSSNOrITIN"
};
cellLitCtrl_7.Controls.Add(SSNOrITINStr);
boxSSNOrITIN = new TextBox
{
CssClass = "dplatypus-webform-field-input",
ID = "txtbxSSNOrITIN",
Width = 80,
MaxLength = 12
};
cellTxtbx_7.Controls.Add(boxSSNOrITIN);
dynamicTable.Rows.Add(row7);
This code produces what you see here:
But I want the textbox (the yellow one) to be snug up against its label ("SSN" in the screamshot, but it can also be "ITIN" depending on the state of the "Employee?" checkbox).
So what we have here is an HtmlTableRow with two elements (the "Mail Stop:" label and its "associated" Textbox) and another HtmlTableRow with three elements (the checkbox, label, and textbox).
The second HtmlTableRow is obviously taking its layout cue from the one above (aligning cells to to the same X coordinate value), but why? And how can I circumvent that? I want the second row to look like this:
|_| Employee? SSN |___________|
...not like this:
|_| Employee? SSN |___________|
How can I "snug up" the label ("SSN") and the following Textbox?
I tried putting the label and textbox in the same HtmlTableCell, but it blew up at runtime when I tried to add two Controls to a single HtmlTableCell.
For the most part, it's nice that the supposedly "independent" HtmlTableRows horizontally line up with each other, but I don't know why/how they do that, nor how to bypass that usually-desirable feature.
HtmlTableCell seems to have a ColSpan property. You may try setting that on the other rows to format it the way you would like:
https://msdn.microsoft.com/en-us/library/system.web.ui.htmlcontrols.htmltablecell.colspan(v=vs.110).aspx
This is not really an answer to my specific question (I didn't find a way to do that), but this is the solution I ended up with: adding these controls to the page not as part of a table, but "standalone":
// These elements were not aligning right as row 7 of the section 1 table, so I am just adding them one by one
CheckBox ckbxEmployeeQ = new CheckBox
{
CssClass = "dplatypus-webform-field-input",
ID = "ckbxEmp",
};
ckbxEmployeeQ.Text = "Employee?";
this.Controls.Add(ckbxEmployeeQ);
AddVerticalSpace();
var SSNOrITINStr = new Label
{
CssClass = "dplatypus-webform-field-label",
Text = "ITIN:",
ID = "lblSSNOrITIN"
};
SSNOrITINStr.Style.Add("padding", "2px");
this.Controls.Add(SSNOrITINStr);
boxSSNOrITIN = new TextBox
{
CssClass = "dplatypus-webform-field-input",
ID = "txtbxSSNOrITIN",
Width = 80,
MaxLength = 12
};
this.Controls.Add(boxSSNOrITIN);
AddVerticalSpace();
this code creates a textbox dynamically based on the total number of items in a listview. my problem is how can i access these textboxes so i can save the contents of the textbox to my database?
int f = 24;
int j = 25;
for (int gg = 0; gg < listView1.Items.Count;gg++ )
{
j = f + j;
TextBox txtb = new TextBox();
txtb.Name = "tboxl1"+gg;
txtb.Location = new Point(330,j);
txtb.Visible = true;
txtb.Enabled = true;
txtb.Font = new Font(txtb.Font.FontFamily,12);
groupBox2.Controls.Add(txtb);
}
I'd be more inclined to write you code like this:
var f = 24;
var j = 25;
var textBoxes =
Enumerable
.Range(0, listView1.Items.Count)
.Select(gg =>
{
j = f + j;
var txtb = new TextBox();
txtb.Name = String.Format("tboxl1{0}", gg);
txtb.Location = new Point(330, j);
txtb.Visible = true;
txtb.Enabled = true;
txtb.Font = new Font(txtb.Font.FontFamily, 12);
return txtb;
})
.ToList();
textBoxes.ForEach(txtb => groupBox2.Controls.Add(txtb));
Now you have a variable textBoxes that saves references to the new text boxes. You can use that to get the values from the text boxes to save them to your database.
If you want all TextBox controls then:
foreach (Control control in groupBox2.Controls)
{
if (control is TextBox)
{
string value = (control as TextBox).Text;
// Save your value here...
}
}
But if you want a specific TextBox, you can get it by its name like this:
Control control = groupBox1.Controls.Find("textBox1", false).FirstOrDefault(); // returns null if no control with this name exists
TextBox textBoxControl = control as TextBox; // if you want TextBox control
string value = control.Text;
// Now you can save your value anywhere
You can get the reference to text box as follows,
Control GetControlByName(string Name)
{
foreach(Control c in this.Controls)
if(c.Name == Name)
return c;
return null;
}