WinForm Application Get value from dynamic textbox - c#

This has been a real struggle lately for me because this is what I need the most right now. I made 2 textboxes dynamic for a login form and want to get the values from the textboxes if I hit the login button. I have searched on the internet for possible values but none of them seem to work for me. The button and the textbox are made in a different class and that is the painful part for me. I cannot get the value from the textbox on the form to the event handler in the class where my buttons are made. If someone can help me with this one so I can go on with my project and be finish it off very soon.
I will leave some pieces of the code also for you. These pieces will be the class for the buttons and textboxes and the main form.
Main Form
x_loc = 0;
y_loc = 80;
x_size = 100;
y_size = 20;
foreach(string item in lon.loginLbls())
{
clsLbl = new Labels(pnlMenu, x_loc, y_loc, x_size, y_size, item);
y_loc += 50;
}
x_loc = 0;
y_loc = 100;
x_size = 200;
y_size = 30;
foreach(string item in lon.loginForm())
{
clsTxt = new Textboxes(pnlMenu, x_loc, y_loc, x_size, y_size, item);
y_loc += 50;
}
x_loc = 0;
y_loc = 200;
x_size = 200;
y_size = 30;
foreach(string item in lon.loginBtns())
{
clsBtn = new Buttons(pnlMenu, x_loc, y_loc, x_size, y_size, item);
y_loc += 50;
}
Button Class
Button btn;
public Buttons(Panel parent, int x_loc, int y_loc, int x_size, int y_size, string name)
{
btn = new Button();
btn.Location = new Point(x_loc, y_loc);
btn.Size = new Size(x_size, y_size);
btn.Text = name;
btn.Name = name;
btn.Click += new EventHandler(btnHandler);
btn.ForeColor = Color.Black;
btn.BackColor = Color.White;
parent.Controls.Add(btn);
}
private void btnHandler(object sender, EventArgs e)
{
Button btn = sender as Button;
switch (btn.Text)
{
case "Login":
Login lgn = new Login();
break;
case "Afsluiten":
Application.Exit();
break;
}
}
Textbox Class
TextBox tb;
public Textboxes(Panel parent, int x_loc, int y_loc, int x_size, int y_size, string name)
{
tb = new TextBox();
tb.Location = new Point(x_loc, y_loc);
tb.Size = new Size(x_size, y_size);
tb.Name = name;
tb.ForeColor = Color.Black;
tb.BackColor = Color.White;
parent.Controls.Add(tb);
}
Lists
public List<string> loginBtns()
{
List<string> lgnBtns = new List<string>();
lgnBtns.Add("Login");
return lgnBtns;
}
public List<string> loginForm()
{
List<string> lgnForm = new List<string>();
lgnForm.Add("username");
lgnForm.Add("password");
return lgnForm;
}
public List<string> loginLbls()
{
List<string> lgnLbl = new List<string>();
lgnLbl.Add("Code");
lgnLbl.Add("Wachtwoord");
return lgnLbl;
}
Note: All these methods are located in a different class.

You have 2 ways to go:
1.Make creation on textboxes public:
partial class form1{
TextBox tb = new TextBox();
...
}
then can get get its text whereever you like:
string a = tb.Text;
2.Get Textbox Controls of Parent:
TextBox[] tb = parent.Controls.OfType<TextBox>().ToArray();
Now you have textboxes in an array. You may want to use the Tag to identify them:
string a = tb.FirstOrDefault(t=>(string)t.Tag=="username").Text;
Of course in this case you must have set the Tag when adding the TextBox.

Related

Check which Radio Button is checked in C#, with dynamically created radiobuttons

I can't find any solution or hint on this problem. Problem described after this code.
I must create one picturebox and radiobutton for every folder found on a specific path:
{
InitializeComponent();
string pathtocircuits = "../../tracks";
string[] allfiles = Directory.GetDirectories(pathtocircuits, "*.*", SearchOption.TopDirectoryOnly);
int imgx = 387;
int imgy = 153;
int radx = 428;
int rady = 259;
String track = "";
String pici = "";
String pic = "pictureBox";
String rad = "radiobutton";
String radr = "";
String picr = "";
foreach (String file in allfiles)
{
track = Path.GetFileName(file);
pici = "../../tracks/" + track + "/p_" + track + ".png";
picr = pic + element.ToString();
radr = rad + element.ToString();
PictureBox pb = new PictureBox();
pb.Location = new System.Drawing.Point(imgx, imgy); ;
pb.Image = Image.FromFile(pici);
pb.Width = 100;
pb.Height = 100;
pb.SizeMode = PictureBoxSizeMode.StretchImage;
pb.Name = picr;
Controls.Add(pb);
RadioButton rdo = new RadioButton();
rdo.Name = radr;
rdo.Text = "";
rdo.Tag = track;
rdo.Location = new Point(radx, rady);
this.Controls.Add(rdo);
element += 1;
imgx += 110;
radx += 110;
}
}
With this part I get to create the elements I need (it works).
My problem is when I press a button to reach Form2. How can I check which radiobutton is selected and store its Tag value in a String?
for(int i = 0; i<element; i++)
{
if( ??? .Checked == true )
{
globalstring = ??? .Tag;
}
}
If I try to use the name of a created radiobutton instead of a ??? it gives me an error like 'element ??? does not have a Checked or Tag attribute'
Add method below
Add to For loop : rdo.CheckedChanged += new EventHandler(radioButton_CheckedChanged);
private void radioButton_CheckedChanged(object sender, EventArgs e)
{
RadioButton button = sender as RadioButton;
string name = button.Text;
}
RadioButtons as any other control are stored in the Controls collection of their container. If you add them directly to the form you can retrieve them using this code.
protected void Button1_Click(object sender, EventArgs e)
{
var radio = this.Controls.OfType<RadioButton>().FirstOrDefault(x => x.Checked);
if(radio != null)
{
string tag = radio.Tag.ToString();
.....
// Form2 = new Form2(tag);
}
}
The radiobuttons are added to a same group by default, so you can get the checked radiobutton as followed.
List<RadioButton> radioButtons = this.Controls.OfType<RadioButton>().ToList();
RadioButton rb = radioButtons
.Where(r => r.Checked)
.Single();
string tag = rb.Tag.ToString();

How to add an item with the button that can delete this item c# winforms

Im trying to make an app that adds shopping items with the price(just for education purpose). I want to add a button as well so that I can delete this item if I want too. this is what Ive done:
class ShopItem
{
string name;
decimal price;
int labelNumber;
public ShopItem(string name, decimal price, int labelNumber)
{
this.name = name;
this.price = price;
this.labelNumber = labelNumber;
}
public string GetName()
{
return name;
}
public decimal GetPrice()
{
return price;
}
public int GetLabelNumber()
{
return labelNumber;
}
}
Then in my main class:
public partial class Form1 : Form
{
List<ShopItem> shopItems = new List<ShopItem>();
List<Button> buttons = new List<Button>();
List<Label> labelsList = new List<Label>();
int shopItemNumber;
int top = 50;
int left = 50;
public Form1()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
this.shopItemNumber = shopItems.Count;
label3.Text = "";
label3.Text = shopItemNumber.ToString();
shopItems.Add(new ShopItem(textBox1.Text, Convert.ToDecimal(textBox2.Text), shopItemNumber));
AddLabel();
AddAButton();
}
void AddAButton()
{
Button newButton = new Button();
buttons.Add(newButton);
newButton.Left = left + 100;
newButton.Top = top;
newButton.Text = "DELETE";
panel1.Controls.Add(newButton);
top += 40;
}
void AddLabel()
{
Label newLabel = new Label();
labelsList.Add(newLabel);
newLabel.Left = left;
newLabel.Top = top;
newLabel.Text = shopItems[shopItemNumber].GetName() + " " + shopItems[shopItemNumber].GetPrice();
panel1.Controls.Add(newLabel);
}
}
Im adding new objects and then checking the list count so that I know each item number. Now I dont know how to make buttons to remove each item. I would also like to know what is the best practice for this type of tasks? I dont want to use database as its too complicated for now, just make it in runtime? How would you, advanced guys, would make it?
I managed to do something like this based on your answers:
public partial class Form1 : Form
{
List<ShopItem> shopItems = new List<ShopItem>();
List<Button> buttons = new List<Button>();
List<Label> labelsList = new List<Label>();
int shopItemID;
int top = 50;
int left = 50;
public Form1()
{
InitializeComponent();
shopItemID = 0;
}
private void Button1_Click(object sender, EventArgs e)
{
int shopItemID = this.shopItemID;
label3.Text = "";
label3.Text = shopItemID.ToString();
decimal price;
if(Decimal.TryParse(textBox2.Text.Replace(",", "."), out price))
{
shopItems.Add(new ShopItem(textBox1.Text, price, shopItemID));
label3.Text = price.ToString();
AddLabel();
AddAButton();
this.shopItemID++;
}
else
{
label3.Text = "Wrong price format provided";
}
}
void AddAButton()
{
Button newButton = new Button();
buttons.Add(newButton);
newButton.Left = left + 100;
newButton.Top = top;
newButton.Text = "DELETE";
panel1.Controls.Add(newButton);
top += 40;
newButton.Tag = this.shopItemID;
newButton.Click += DeleteClicked;
}
void DeleteClicked(object sender, EventArgs e)
{
Button button = (Button)sender;
int itemNumber = (int)button.Tag;
ShopItem item = shopItems[itemNumber];
button.Dispose();
labelsList[itemNumber].Dispose();
}
void AddLabel()
{
Label newLabel = new Label();
labelsList.Add(newLabel);
newLabel.Left = left;
newLabel.Top = top;
newLabel.Text = shopItems[shopItemID].GetName() + " " + shopItems[shopItemID].GetPrice();
newLabel.Tag = this.shopItemID;
panel1.Controls.Add(newLabel);
}
}
It's working as I wanted it. The question is: The way I did it was according to the right coding practice?
The other question is: I would like to add placement functionality so that if some item is deleted other items go up the way. Should I use some position list? Can All of those items be contained within a ShopItem class? I mean, can I add button, label and other stuff withing this class so they all are created at the same time and becomes one object?
First thing you'll want to do is start using IDs instead of the count. The reason is, let's say you have 5 items (0 through 4) and you delete one. Now when you add another new one, it will get #4 because the count is 4 again (before adding the new one to the list), which means you'll have two #4s.
What you'll want to do instead is something like look for the highest existing number and add 1 to it:
this.shopItemNumber = shopItems.Any() ? shopItems.Max(item => item.labelNumber) + 1 : 0;
Now for the Delete button, just pass the item's number to the AddAButton() method:
AddAButton(shopItemNumber);
...and change the method's signature accordingly:
void AddAButton(int itemNumber)
And then in the AddAButton() method, add that number to the Tag property (you'll see why below):
newButton.Tag = itemNumber;
You'll also need to subscribe to the button's Click event:
newButton.Click += DeleteClicked;
Then create the DeleteClicked() method. This is where you'll make use of that Tag property:
void DeleteClicked(object sender, EventArgs e)
{
Button button = (Button)sender;
int itemNumber = (int)button.Tag;
ShopItem item = shopItems.FirstOrDefault(item => item.labelNumber = itemNumber);
if (item != null)
shopItems.Remove(item);
}
You'll also want to clean up the controls. Make sure to Dispose() them after removing them.
You just have to identify what Label belongs to the button.
Make AddLabel return the label it just created:
Label AddLabel()
{
Label newLabel = new Label();
labelsList.Add(newLabel);
newLabel.Left = left;
newLabel.Top = top;
newLabel.Text = shopItems[shopItemNumber].GetName() + " " + shopItems[shopItemNumber].GetPrice();
panel1.Controls.Add(newLabel);
return newLabel;
}
Pass the label to the new button, and add code to remove it. Store the current shopItem in a variable, so you can access it from the removal code.
void AddAButton(Label newLabel)
{
Button newButton = new Button();
buttons.Add(newButton);
newButton.Left = left + 100;
newButton.Top = top;
newButton.Text = "DELETE";
panel1.Controls.Add(newButton);
top += 40;
// Store the current shopItem in the context (for the lambda)
var shopItem = shopItems[shopItemNumber]
newButton.Click += (s, e) => {
panel1.Controls.Remove(newLabel);
panel1.Controls.Remove(newButton);
newLabel.Dispose();
newButton.Dispose();
shopItems.Remove(shopItem);
}
}
Since controls are IDisposable, it is advised to call Dispose after removing them.

Add label under button in a flowLayoutPanel

I need to dynamically create buttons with labels under them in a flowLayoutPanel when i drop a file onto the form. But how do I set the label position to be under the button since the FLP is arranging the controls by itself.. ?
What I've tried:
void Form1_DragDrop(object sender, DragEventArgs e)
{
string[] fileList = e.Data.GetData(DataFormats.FileDrop) as string[];
foreach (string s in fileList)
{
Button button = new Button();
button.Click += new EventHandler(this.button_Click);
fl_panel.Controls.Add(button);
Icon icon = System.Drawing.Icon.ExtractAssociatedIcon(filename);
Bitmap bmp = icon.ToBitmap();
button.BackgroundImage = bmp;
button.Width = 60;
button.Height = 75;
button.FlatStyle = FlatStyle.Flat;
button.BackgroundImageLayout = ImageLayout.Stretch;
int space = 5;
int Yy = button.Location.Y;
int Xx = button.Location.X;
Label label = new Label();
label.Location = new Point(Yy + space, Xx);
//label.Margin.Top = button.Margin.Bottom;
fl_panel.Controls.Add(label);
}
}
The best idea I know of is to implement a custom control that contains both a button and a label that are arranged correctly. Then add the custom control to the FlowLayoutPanel.
public class CustomControl:Control
{
private Button _button;
private Label _label;
public CustomControl(Button button, Label label)
{
_button = button;
_label = label;
Height = button.Height + label.Height;
Width = Math.Max(button.Width, label.Width);
Controls.Add(_button);
_button.Location = new Point(0,0);
Controls.Add(_label);
_label.Location = new Point(0, button.Height);
}
}
You can then add to it like this:
for (int i = 0; i < 10; i++)
{
CustomControl c = new CustomControl(new Button {Text = "Button!"}, new Label {Text = "Label!"});
fl_panel.Controls.Add(c);
}
EDIT:
If you want to listen to button events, try this:
for (int i = 0; i < 10; i++)
{
var button = new Button {Text = "Button " + i};
CustomControl c = new CustomControl(button, new Label {Text = "Label!"});
button.Click += buttonClicked;
fl_panel.Controls.Add(c);
}
...
private void buttonClicked(object sender, EventArgs e)
{
MessageBox.Show(((Button) sender).Text);
}

Dynamic button, textbox and picturebox creation

Here I am doing a project where questions are presented in images. When the project loads, "start exam" button will be present in the screen. After pressing the button, it should create a picturebox, a textbox and a button for each image from specified path. Then users has to enter the answer in a textbox which is created dynamically. After the dynamic submit button is clicked for every image, the textbox values have to be stored in the listbox. I don't know how get the values from textbox. Can anyone help me out from this?
Here is my code:
PictureBox[] pics = new PictureBox[100];
TextBox[] txts = new TextBox[100];
Button[] butns = new Button[100];
FlowLayoutPanel[] flws = new FlowLayoutPanel[100];
private void button1_Click( Object sender , EventArgs e)
{
for (int i = 0; i < listBox1.Items.Count; i++)
{
flws[i] = new FlowLayoutPanel();
flws[i].Name = "flw" + i;
flws[i].Location = new Point(3,brh);
flws[i].Size = new Size(317,122);
flws[i].BackColor = Color.DarkCyan;
flws[i].BorderStyle = BorderStyle.Fixed3D;
pics[i] = new PictureBox();
pics[i].Location = new Point(953, 95 + brh);
pics[i].Name = "pic" + i;
pics[i].Size = new Size(300, 75);
pics[i].ImageLocation = "C:/" + listBox1.Items[i];
flws[i].Controls.Add(pics[i]);
txts[i] = new TextBox();
txts[i].Name = "txt" + i;
txts[i].Location = new Point(953, 186 + brh);
flws[i].Controls.Add(txts[i]);
butns[i] = new Button();
butns[i].Click += new EventHandler(butns_Click);
butns[i].Text = "submit";
butns[i].Name = "but" + i;
butns[i].Location = new Point(1100, 186 + brh);
flws[i].Controls.Add(butns[i]);
flowLayoutPanel1.Controls.Add(flws[i]);
brh += 130;
}
}
private void butns_Click(object sender, EventArgs e)
{
Button butns = sender as Button;
TextBox txts = sender as TextBox;
listBox2.Items.Add("text values " + txts.Text.ToString());
}
I would create a usercontrol to combine the controls.
Search for "custom usercontrol c#"
Regards.
Try this...
private void butns_Click(object sender, EventArgs e)
{
Button butns = sender as Button;
string btnName = butns.Name;
string Id = btnName.Substring(3);
string txtName = "txt" + Id;
listBox2.Items.Add("text values " + GetValue(txtName));
}
private string GetValue(string name)
{
TextBox txt = new TextBox();
txt.Name = name;
foreach (Control ctl in this.Controls)
{
if (ctl is FlowLayoutPanel)
{
foreach (Control i in ctl.Controls)
{
if (((TextBox)i).Name == txt.Name)
{
txt = (TextBox)i;
return txt.Text;
}
}
}
}
return txt.Text;
}

C# deleting dynamic textboxes by checkboxing

I am writing a code in C# I have 2 Forms and the code creates textboxes and corresponding checkboxes dynamically. The code I wrote creates dynamic textboxes and checkboxes successfully. However, I am not able to delete the row of textboxes in a selected checkbox line.
public void CreateTextBox(int i, StringReader sr)
{
ProductForm form2 = new ProductForm();
_cb = new CheckBox[i];
form2.Visible = true;
form2.Activate();
int x = 10;
int y = 30;
int width = 100;
int height = 20;
for (int n = 0; n < i; n++)
{
String line = sr.ReadLine();
String[] line_ = line.Split(new char[] {'\t'});
String cbName = "chkBox_" + n.ToString();
_cb[n] = new CheckBox();
_cb[n].Name = cbName;
_cb[n].Location = new Point(2, y);
_cb[n].Checked = false;
form2.Controls.Add(_cb[n]);
if (line.Length > 3)
{
for (int row = 0; row < 4; row++)
{
String name = "txtBox_" + row.ToString();
TextBox tb = new TextBox();
tb.Name = name;
tb.Text = line_[row].ToString();
tb.Location = new Point(x, y);
tb.Height = height;
if (row == 1)
{
tb.Width = width * row;
}
if (row == 3)
{
tb.Width = width * 5;
}
else
{
tb.Width = width - 20;
}
x += 10 + width;
form2.Controls.Add(tb);
}
}
x = 10;
y += 25;
}
}
private void DeleteTextBoxButton_Click(object sender, EventArgs e)
{
//Here should I add a code in order to delete dynamically created
//textboxes by clicking checkbox and button
}
}
Not sure of your question. But if I am right, this could do the trick.
SOLUTION1: While creating all the controls, add them to a List<Controls>. When you are checking the checkbox to delete the row, get the name of the checkbox, search it in the List<Controls>. So this way can get the index of the row of the checkbox clicked. Now delete the controls of that rows.
SOLUTION2: Create your controls in a TablelayoutPanel and everything will be easy.
EDIT
Copy paste everything in the form1, se btn_click as a event handler for a button. Let the size of the form a bit big. Everything should work fine now. If not working, let me know.
class MyControl
{
public TextBox txt1 { get; set; }
public TextBox txt2 { get; set; }
public TextBox txt3 { get; set; }
public TextBox txt4 { get; set; }
public CheckBox cb { get; set; }
public MyControl(TextBox txt1, TextBox txt2, TextBox txt3, TextBox txt4, CheckBox cb)
{
this.txt1 = txt1;
this.txt2 = txt2;
this.txt3 = txt3;
this.txt4 = txt4;
this.cb = cb;
}
}
List<MyControl> list = new List<MyControl>();
public int x = 50, n = 1;
TextBox txtTemp, txt1, txt2, txt3, txt4;
CheckBox cbTemp;
private void btn_Click(object sender, EventArgs e)
{
txtTemp = new TextBox();
txtTemp.Location = new System.Drawing.Point(10, x);
txtTemp.Name = "txt1_" + n;
txt1 = txtTemp;
txtTemp = new TextBox();
txtTemp.Location = new System.Drawing.Point(120, x);
txtTemp.Name = "txt2_" + n;
txt2 = txtTemp;
txtTemp = new TextBox();
txtTemp.Location = new System.Drawing.Point(230, x);
txtTemp.Name = "txt3_" + n;
txt3 = txtTemp;
txtTemp = new TextBox();
txtTemp.Location = new System.Drawing.Point(350, x);
txtTemp.Name = "txt4_" + n;
txt4 = txtTemp;
cbTemp = new CheckBox();
cbTemp.Name = "cb1_" + n;
cbTemp.Enter += new EventHandler(cbTemp_Enter);
cbTemp.Location = new System.Drawing.Point(490, x);
this.Controls.Add(txt1);
this.Controls.Add(txt2);
this.Controls.Add(txt3);
this.Controls.Add(txt4);
this.Controls.Add(cbTemp);
list.Add(new MyControl(txt1, txt2, txt3, txt4, cbTemp));
x += 40;
n++;
}
void cbTemp_Enter(object sender, EventArgs e)
{
if ((MessageBox.Show("Are you Sure?", "Warning", MessageBoxButtons.YesNo)) == DialogResult.No)
return;
CheckBox cbMain = (CheckBox)sender;
int index = Search(cbMain);
this.Controls.Remove(list[index].txt1);
this.Controls.Remove(list[index].txt2);
this.Controls.Remove(list[index].txt3);
this.Controls.Remove(list[index].txt4);
this.Controls.Remove(list[index].cb);
}
private int Search(CheckBox cbMain)
{
int temp = 0;
foreach (MyControl item in list)
{
if(cbMain.Name == item.cb.Name)
temp = list.IndexOf(item);
}
return temp;
}
For WinForms, I recommend putting the generated TextBoxes into the Tag field of the CheckBox. Then keep a managed list of all CheckBoxes. Once they click the delete button, iterate through the collection of CheckBoxes. If their state is checked, pull the TextBox out of the Tag field, remove it from the form collection, then delete it.
NOTE: This code is untested but should work in principle.
UPDATE: Reading your latest comment, instead of storing a single TextBox in the Tag, just create another List of them and store the entire list in the tag. Then iterate through those in the delete method.
private List<CheckBox> _checkboxes = new List<CheckBox>();
public void CreateTextBox( int i, StringReader r )
{
// ... do your stuff here
_cb[n].Tag = tb;
// ... finish up
_checkboxes.Add( _cb[n] );
}
public void DeleteTextBoxButton_Click( object sender, EventArgs e )
{
foreach( var cb in _checkboxes )
{
if( cb.Checked )
{
TextBox tb = cb.Tag as TextBox;
if( tb != null )
{
form2.Controls.Remove( tb );
}
}
}
}

Categories