I'm trying to get the values that a user inputs in a textbox in a dynamically generated form. Another method loads and parses an XML file and creates an object that has specific getters and setters for the settings that it finds in the file (Server, Port, Title, etc.).
The dynamic form is created using labels and textboxes like this. It was designed only to display the information from the XML file, and I am trying to implement a system that allows users to edit the information before saving it again to the file. I'm doing alright with the methods to save and edit the XML file, but I'm lost for how to associate the input in any given textbox with the associated label representing the key in the XML file to change.
Below is the current form implementation where the labels and textboxes are created as part of a foreach loop. I tried creating textbox.Leave eventHandler to track when the user has finished changing a value, but I can't figure out how to know what label it is associated with.
var sortedSettings = new SortedDictionary<string, string>(theSettings.Settings);
int numSettings = sortedSettings.Count;
TextBox[] txt = new TextBox[numSettings];
Label[] label = new Label[numSettings];
int labelSpacing = this.labelSecond.Top - this.labelTop.Bottom;
int textSpacing = this.textBoxSecond.Top - this.textBoxTop.Bottom;
int line = 0;
foreach (KeyValuePair<string, string> key in sortedSettings)
{
label[line] = new Label();
label[line].Text = key.Key;
label[line].Left = this.labelTop.Left;
label[line].Height = this.labelTop.Height;
label[line].Width = this.labelTop.Width;
txt[line] = new TextBox();
txt[line].Text = key.Value;
txt[line].Left = this.textBoxTop.Left;
txt[line].Height = this.textBoxTop.Height;
txt[line].Width = this.textBoxTop.Width;
txt[line].ReadOnly = false;
// Attach and initialize EventHandler for template textbox on Leave
txt[line].Leave += new System.EventHandler(txt_Leave);
if (line > 0)
{
label[line].Top = label[line - 1].Bottom + labelSpacing;
txt[line].Top = txt[line - 1].Bottom + textSpacing;
}
else
{
label[line].Top = this.labelTop.Top;
txt[line].Top = this.textBoxTop.Top;
}
this.Controls.Add(label[line]);
this.Controls.Add(txt[line]);
line++;
}
private void txt_Leave(object sender, EventArgs e)
{
String enteredVal = sender;
FormUtilities.FindAndCenterMsgBox(this.Bounds, true, "EventChecker");
MessageBox.Show("The current value of LABEL is " + enteredVal, "EventChecker");
}
One option is to use TextBox.Tag property.
Example (in foreach loop):
txt[line] = new TextBox();
txt[line].Text = key.Value;
txt[line].Tag = label[line];
To get label associated with TextBox:
TextBox t = txt[0];
Label l = t.Tag as Label;
//Here is how you identify textbox which generated the event.
private void txt_Leave(object sender, EventArgs e)
{
TextBox tb = sender as TextBox;
//..
}
Related
I have a form application where multiple DataGridView objects are to be displayed (but not at once). They should be created on top of each other and it should then be possible to toggle the displayed DataGridView using a ComboBox.
I have a function which should create new DataGridView every time its called and then adds the name to the ComboBox:
private void readCSV(string DBname)
{
DataGridView tagDBname = new DataGridView();
tagDBname.Location = new System.Drawing.Point(24, 260);
tagDBname.Name = DBname;
tagDBname.Size = new System.Drawing.Size(551, 217);
tagDBname.TabIndex = 6;
tagDBname.Columns.Add("Column1", "Col1");
tagDBname.Columns.Add("Column2", "Col2");
tagDBname.Visible = false;
comboBoxTag.Items.Add(DBname);
}
Then I would like to change the visibility state of a DataGridView given the selected name from the ComboBox. This should be done in the function called when the index changes:
private void comboBoxTag_SelectedIndexChanged(object sender, EventArgs e)
{
// Get the name of the DataGridView which should be visible:
string selectedTagDB = comboBoxTagDatabases.SelectedItem.ToString();
DataGridView tagDatabase = ? // Here the DataGridView should be selected given the name "selectedTagDB"
tagDatabase.Visible = true;
}
In the above, I do not know how to assign the DataGridView only given its name. Any help would be appreciated - even if it means that the selected approach is inappropriate of what I am trying to achieve. If the question is answered elsewhere, feel free to guide me in the right direction :)
I would store the gridviews in a dictionary by using the DB name as key;
private readonly Dictionary<string, DataGridView> _tagDBs =
new Dictionary<string, DataGridView>();
private void readCSV(string DBname)
{
DataGridView tagDBname = new DataGridView();
// Add the gridview to the dictionary.
_tagDBs.Add(DBname, tagDBname);
tagDBname.Name = DBname;
tagDBname.Location = new System.Drawing.Point(24, 260);
tagDBname.Size = new System.Drawing.Size(551, 217);
tagDBname.TabIndex = 6;
tagDBname.Columns.Add("Column1", "Col1");
tagDBname.Columns.Add("Column2", "Col2");
tagDBname.Visible = false;
this.Controls.Add(tagDBname); // Add the gridview to the form ot to a control.
comboBoxTag.Items.Add(DBname);
}
private void comboBoxTag_SelectedIndexChanged(object sender, EventArgs e)
{
// Get the name of the DataGridView which should be visible:
string selectedTagDB = comboBoxTagDatabases.SelectedItem.ToString();
foreach (DataGridView dgv in _tagDBs.Values) {
dgv.Visible = dgv.Name == selectedTagDB; // Hide all gridviews except the selected one.
}
}
If you need to do something with the selected gridview, you can get it with:
if (_tagDBs.TryGetValue(selectedTagDB, out DataGridView tagDatabase)) {
// do something with tagDatabase.
}
Note: you must add the gridview to the form or to a container control on the form. E.g.
this.Controls.Add(tagDBname);
You can loop through all DataGridViews of the form to display the expected one using its name, while hidding the others ones.
This solution isn't pretty but works
private void ShowOneDataGridViewAndHideOthers(string name)
{
foreach (var DGV in this.Controls.OfType<DataGridView>())
{
DGV.Visible = DGV.Name == name;
}
}
And call it this way :
private void comboBoxTag_SelectedIndexChanged(object sender, EventArgs e)
{
// Get the name of the DataGridView which should be visible:
string selectedTagDB = comboBoxTagDatabases.SelectedItem.ToString();
ShowOneDataGridViewAndHideOthers(selectedTagDB);
}
The method can be made a bit more generic this way :
private void ShowOneControlAndHideOthers<T>(string name, Control controls) where T : Control
{
foreach (var control in controls.Controls.OfType<T>())
{
control.Visible = control.Name == name;
}
}
private void comboBoxTag_SelectedIndexChanged(object sender, EventArgs e)
{
// Get the name of the DataGridView which should be visible:
string selectedTagDB = comboBoxTagDatabases.SelectedItem.ToString();
ShowOneControlAndHideOthers<DataGridView>(selectedTagDB, this);
}
I have an application where the user can add any number of tabpages depending on what he/she needs. These tabpages have identical controls (textboxes and labels).
The controls on each tabpages are named like this: (on tabpage1 the controls are named: txtServer1, txtPort1, txtUser1, txtDbName1. if the user clicks the 'add another connection button' the application creates a second tabpage and the controls will be named: txtServer2, txtPort2, txtUser2, txtDbName2) and so on...
for example if the user have multiple tabpages to set-up:
the user clicks the 'add another connection' and the another tabpage with identical controls has been created and the user fills it up with appropriate data:
same thing goes here:
here's the code for dynamically added tabpage with controls:
//when 'add another connection' button is clicked
private void btnAddConnection_Click(object sender, EventArgs e)
{
string tabTitle = "Connection " + (tabControl1.TabCount + 1).ToString();
TabPage tabPage = new TabPage(tabTitle);
tabControl1.TabPages.Add(tabPage);
}
//when another tabpage has been added to tabcontrol
private void tabControl1_ControlAdded(object sender, ControlEventArgs e)
{
//control instances
TextBox txtServer = new TextBox();
TextBox txtPort = new TextBox();
TextBox txtUser = new TextBox();
TextBox txtDbName = new TextBox();
Label lblServer = new Label();
Label lblPort = new Label();
Label lblUser = new Label();
Label lblDbName = new Label();
tabControl1.SelectedTab = tabControl1.TabPages[tabControl1.TabCount - 1]; //select the newly addded tabpage
tabControl1.SelectedTab.BackColor = tabPage1.BackColor; //tabpage background color
//lblServer Properties
lblServer.Location = lblServer1.Location;
lblServer.Text = lblServer1.Text;
lblServer.ForeColor = lblServer1.ForeColor;
lblServer.Name = "lblServer" + tabControl1.TabCount.ToString();
//lblPort Properties
lblPort.Location = lblPort1.Location;
lblPort.Text = lblPort1.Text;
lblPort.ForeColor = lblPort1.ForeColor;
lblPort.Name = "lblPort" + tabControl1.TabCount.ToString();
//lblUser Properties
lblUser.Location = lblUser1.Location;
lblUser.Text = lblUser1.Text;
lblUser.ForeColor = lblUser1.ForeColor;
lblUser.Name = "lblUser" + tabControl1.TabCount.ToString();
//lblDbName Properties
lblDbName.Location = lblDbName1.Location;
lblDbName.Text = lblDbName1.Text;
lblDbName.ForeColor = lblDbName1.ForeColor;
lblDbName.Name = "lblDbName" + tabControl1.TabCount.ToString();
//txtserver properties
txtServer.Location = txtServer1.Location;
txtServer.Width = txtServer1.Width;
txtServer.Height = txtServer1.Height;
txtServer.Font = txtServer1.Font;
txtServer.Name = "txtServer" + tabControl1.TabCount.ToString();
//txtport properties
txtPort.Location = txtPort1.Location;
txtPort.Width = txtPort1.Width;
txtPort.Height = txtPort1.Height;
txtPort.Font = txtPort1.Font;
txtPort.Name = "txtPort" + tabControl1.TabCount.ToString();
//txtuser properties
txtUser.Location = txtUser1.Location;
txtUser.Width = txtUser1.Width;
txtUser.Height = txtUser1.Height;
txtUser.Font = txtUser1.Font;
txtUser.Name = "txtUser" + tabControl1.TabCount.ToString();
//txtdbname properties
txtDbName.Location = txtDbName1.Location;
txtDbName.Width = txtDbName1.Width;
txtDbName.Height = txtDbName1.Height;
txtDbName.Font = txtDbName1.Font;
txtDbName.Name = "txtUser" + tabControl1.TabCount.ToString();
//add controls to tabpage
tabControl1.SelectedTab.Controls.Add(lblServer);
tabControl1.SelectedTab.Controls.Add(lblPort);
tabControl1.SelectedTab.Controls.Add(lblUser);
tabControl1.SelectedTab.Controls.Add(lblDbName);
tabControl1.SelectedTab.Controls.Add(txtServer);
tabControl1.SelectedTab.Controls.Add(txtPort);
tabControl1.SelectedTab.Controls.Add(txtUser);
tabControl1.SelectedTab.Controls.Add(txtDbName);
}
When the user clicks the save button, I want the application to read each text in the textboxes (except for that url text) so that I can save it to a configuration file.
all I can think of is this
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
string connection;
for (int i = 1; i <= tabControl1.TabCount; i++ )
{
connection = "server=" + txtServer[i].Text + ";port=" txtPort[i].Text + ";user=" + txtUser[i].Text + ";dbname=" + txtDbName[i];
//save to config file code goes here...
}
}
and I know this is not correct.
any solution for this? thanks :)
This is the simplest way you can try this just use below function to get text from control in tabpage
public string getValue(string controlName, TabPage selectedTab)
{
if (selectedTab.Controls.ContainsKey(controlName)){
TextBox selectedtb = (TextBox)selectedTab.Controls[controlName];
return selectedtb.Text;
}
else
return null;
}
and in your save code use it like below
string connection;
int i = 1;
TabControl.TabPageCollection pages = tabControl1.TabPages;
foreach (TabPage page in pages)
{
connection = "server=" + getValue("txtServer"+i,page) + ";port=" +getValue("txtPort"+i,page) + ";user=" + getValue("txtUser"+i,page) + ";dbname=" + getValue("txtDbName"+i,page);
i++;
//save to config file code goes here...
}
txtServer[i].Text it's true but You have not defined an array.
You can do it like this
//global
List<TextBox> txtServerList= new List<TextBox>();
private void tabControl1_ControlAdded(object sender, ControlEventArgs e)
{
txtServer.Location = txtServer1.Location;
txtServer.Width = txtServer1.Width;
txtServer.Height = txtServer1.Height;
txtServer.Font = txtServer.Font;
txtServer.Name = "txtServer" + tabControl1.TabCount.ToString();
txtServerList.Add(txtServer)
.
.
.
}
Finally
for (int i = 1; i <= tabControl1.TabCount; i++ )
{
connection=txtServerList.get(i).Text + ......
}
You could just loop over the controls and find the matching name, something like this:
foreach(var page in tabControl1.TabPages){
var server = ProcessControls(page.Controls, "txtServer");
//... continue with the others
}
private TextBox ProcessControls(Control ctrlContainer, string name)
{
foreach (Control ctrl in ctrlContainer.Controls)
{
if (ctrl.GetType() == typeof(TextBox))
{
if(ctrl.Name.StartsWith(name))
return (TextBox)ctrl;
}
}
}
You can use an ArrayList to store and access all dynamically added controls. Set a name for each dynamically added controls. It can be based on the size of ArrayList.
I will not show the exact systax of c#.
first
declare an ArrayList or List(Type Safe)
List<Button> buttons = new List<Button>();
We just created a storage for our buttons that will be added at runtime.
void your_event (some parameters) {
Button temp = new Button("Hello");
temp.Name="button_name";
YourMainPanel.Controls.add(temp);
//after creating your button add it to the parent container. of any control where you want this button to be added.
//you can also set the coordinates of the button if you like
//after creating the button we need to add it to our List so that we can
//access it later, since the value of the 'temp' will change after this
//event was invoked in the future.
buttons.add(temp);
}
There are several ways to get the items in List<T>. One is by using index.
void someMethod(some parameters) {
Button button = buttons.ElementAt(index);
}
I got some code to create new buttons programmatically.
foreach (DataRow dtRow in dtTable.Rows)
{
string question_id = Convert.ToString(dtRow["QUESTION_ID"]);
string question_text = Convert.ToString(dtRow["QUESTION_TEXT"]);
var btn_system = new Button
{
ID = "btn_question" + question_id,
Text = question_text,
CssClass = "quest_buttons"
};
btn_system.Command += ButtonClick_Parent;
btn_system.CommandArgument = Convert.ToString(question_id);
}
Now I would like to add multiple CommandArgument in line 12 of my code snippet. How can I do this from code behind?
Thanks in advance!
You need to pass multiple arguments as a string separating by some character and in event handler, you need to parse them. I have shown here using comma
btn_system.CommandArgument = "argument1,argument2,argument2,...";
then get this using below code
protected void ButtonClick_Parent(object sender, EventArgs e)
{
Button button = (Button)sender;
string[] commandArgs = button.CommandArgument.ToString().Split(',');
}
I have dynamic drop down lists that are created based on what's selected in the list box.. When clicking confirm this is when the drop down lists are created. Clicking save is where I attempt to retrieve the values. However I am unable to retrieve that values that are in the drop down lists.
Code:
protected void btnConfirm_Click(object sender, EventArgs e)
{
int ID = 0;
foreach (string value in values)
{
MyStaticValues.alEdit.Add(value);
CreateEditForm(value, ID);
ID += 1;
}
if (values.count != 0)
{
btnSave.Visible = true;
btnConfirm.Enabled = false;
}
}//End of btnConfirm_Click
protected void CreateEditForm(string Value, int ID)
{//Creates an edit form for the value inserted.
string name = value;
//This part adds a header
phEditInventory.Controls.Add(new LiteralControl("<h2>" + name + "</h2>"));
phEditInventory.Controls.Add(new LiteralControl("<div class=\"clearfix\"></div>"));
//Create a label
Label lblName = new Label();
lblName.Text = "Name";
lblName.ID = "lblName" + ID;
lblName.CssClass = "control-label";
//Create a Drop Down List
DropDownList ddlName = new DropDownList();
ddlName.ID = "ddlName" + ID;
ddlName.CssClass = "form-control";
//Set default N/A Values For Drop Down List
ddlName.Items.Add(new ListItem("N/A", Convert.ToString("0")));
//The Rest of the Values are populated with the database
//Adds the controls to the placeholder
phEditInventory.Controls.Add(lblName);
phEditInventory.Controls.Add(ddlName);
phEditInventory.Controls.Add(new LiteralControl("<div class=\"clearfix\"></div>"));
} //End of CreateEditForm
protected void btnSave_Click(object sender, EventArgs e)
{
string name = "";
try
{
for (int i = 0; i < MyStaticValues.alEdit.Count; i++)
{
string nameID = "ddlName" + i.ToString();
DropDownList ddlName = (DropDownList)phEditInventory.FindControl(nameID);
name = ddlName.SelectedValue.ToString();
}
}
catch (Exception ex)
{
}
phEditInventory.Visible = false;
btnSave.Visible = false;
MyStaticValues.alEdit.Clear();
}//End of btnSave_Click Function
Your problem is that the dynamically created dropdown lists are not maintained on postback. When you click the Save button, a postback occurs, and the page is re-rendered without the dynamically created dropdowns. This link may help.
Maintain the state of dynamically added user control on postback?
I have a radio buttons and one text box on a panel made dynamically . Now, I want to disable the text box when the second radio button is checked, means they are both connected. how can I make the event for it. I want to have the event working.
Thanks a lot in advanced.
this is my code which is not working:
Panel pnl = new Panel();
pnl.Name = "pnl_";
pnl.Size = new Size(630, 80);
RadioButton rd = new RadioButton();
rd.Name = "rd_" + dr[i]["Value_Name"].ToString();
rd.Text = dr[i]["Value_Name"].ToString();
rd.Location = new Point(i,i*2);
pnl.Controls.Add(rd);
TextBox txt = new TextBox();
txt.Name = "txt_" + Field_Name+"_"+dr[i]["Value_Name"].ToString();
txt.Size = new Size(171, 20);
txt.Text = Field_Name + "_" + dr[i]["Value_Name"].ToString();
txt.Location = new Point(20, 30);
pnl.Controls.Add(txt);
////// ???? ////////
rd.CheckedChanged += new EventHandler(eventTxt(txt));
void eventTxt(object sender,EventArgs e,TextBox txt)
{
RadioButton rd = (RadioButton)sender;
txt.Enabled = rd.Checked;
}
Use a lambda to close over the relevant variable(s):
rd.CheckedChanged += (s, args) => txt.Enabled = rd.Checked;
If you had more than a one line implementation, you could call out to a method accepting whatever parameters you've closed over, instead of including it all inline.
I would suggest to set the Tag of the radio button and get walk down the dependencies.
rd.Tag = txt;
In the event handler use this:
TextBox txt = (sender as Control).Tag as TextBox;
txt.Enabled = ...
you can use code given
rd.CheckedChanged += (s,argx) => txt.Enabled = rd.Checked;
Here's how you could create an event for it:
//if you are using Microsoft Visual Studio, the following
//line of code will go in a separate file called 'Form1.Design.cs'
//instead of just 'Form1.cs'
myTextBox.CheckChangedEventHandeler += new EventHandeler(checkBox1_CheckChanged); //set an event handeler
public void checkBox1_CheckChanged(object sender, EventArgs e) //what you want to happen every time the check is changed
{
if(checkBox1.checked == true) //replace 'checkBox1' with your check-box's name
{
myTextBox.enabled = false; //replace 'myTextbox' with your text box's name;
//change your text box's enabled property to false
}
}
Hope it helps!