Get text from dynamically created TextBox - c#

I have a button when clicked creates textboxes dynamically:
for (int i = 0; i < length; i++)
{
Name.Add(new TextBox());
System.Drawing.Point locate = new System.Drawing.Point(137, 158 + i * 25);
(Name[i] as TextBox).Location = locate;
(Name[i] as TextBox).Size = new System.Drawing.Size(156, 20);
StartTab.Controls.Add(Name[i] as TextBox);
}
I want to get the text entered in Name[i] convert to a string then set it to labels

You can use Control.ControlCollection.Find.
UPDATED:
TextBox txtName = (TextBox)this.Controls.Find("txtNameOfTextbox", true)[0];
if (txtName != null)
{
return txtName.Text;
}

You don't say what type that Name is, it looks like a list of some sort. Try using a List<TextBox> that way you can just access the TextBox properties directly. Something like this. I am also not sure what Control that StartTab is, so I just used a Panel for this test code. (you should also be aware that Name masks the Form's Name property that is why I changed your list to name)
public partial class Form1 : Form
{
List<TextBox> name = new List<TextBox>();
int length = 5;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < length; i++)
{
name.Add(new TextBox() { Location = new System.Drawing.Point(137, 158 + i * 25),
Size = new System.Drawing.Size(156, 20) });
StartTab.Controls.Add(name[i]);
}
}
private void button2_Click(object sender, EventArgs e)
{
for (int i = 0; i < length; i++)
{
StartTab.Controls.Add(new Label() {Location = new System.Drawing.Point(name[i].Location.X + name[i].Width + 20,
name[i].Location.Y),
Text = name[i].Text,
AutoSize = true });
}
}
}

Related

Why will this code not work when trying to add labels to panels

The screenshot shows part of my code and I am getting the error cannot be used as a method and I'm not sure how to fix it. I want to add labels to the panels that are created for a calendar. Any help will be appreciated.
public partial class frmDisplayAppointment : Form
{
public frmDisplayAppointment()
{
InitializeComponent();
}
private List<FlowLayoutPanel> listFlDay = new List<FlowLayoutPanel>();
private void DisplayAppointment_Load(object sender, EventArgs e)
{
GenerateDayPanel(42);
AddLabelDayToFlDay(1);
}
private void GenerateDayPanel(int totalDays)
{
flDays.Controls.Clear();
for (int i = 1; i <= totalDays; i++)
{
FlowLayoutPanel fl = new FlowLayoutPanel();
fl.Name = $"flDay{i}";
fl.Size = new Size(94, 70);
fl.BackColor = Color.White;
fl.BorderStyle = BorderStyle.FixedSingle;
flDays.Controls.Add(fl);
listFlDay.Add(fl);
}
}
private void AddLabelDayToFlDay(int startDay)
{
int day = 1;
for (int i = startDay; i <= listFlDay.Count - 1; i++)
{
Label lbl = new Label();
lbl.Name = $"lblDay{i}";
lbl.AutoSize = false;
lbl.TextAlign = ContentAlignment.MiddleRight;
lbl.Size = new Size(95, 23);
lbl.Text = day.ToString() ;
//ERROR HERE
listFlDay(i).Controls.Add(lbl);
day += 1;
}
}
Many thanks

How to use array of textbox in button_click method?

I've create an array of textboxes of rows and colums in EnterColsAndRows class. I need to use it in button_click method to create an array of int variables for each row and column.
public partial class EnterColsAndRows : Form
{
public int width_of_nonogram;
public int height_of_nonogram;
public EnterColsAndRows(int width, int height)
{
InitializeComponent();
width_of_nonogram = width;
height_of_nonogram = height;
TextBox[] textBox1 = new TextBox[width_of_nonogram];
TextBox[] textBox2 = new TextBox[height_of_nonogram];
for (int i = 0; i < width_of_nonogram; i++)
{
textBox1[i] = new TextBox();
textBox1[i].Text = "Col " + (i + 1);
Point p = new Point(20, 30 * i);
textBox1[i].Location = p;
this.Controls.Add(textBox1[i]);
}
for (int i = 0; i < height_of_nonogram; i++)
{
textBox2[i] = new TextBox();
textBox2[i].Text = "Row " + (i + 1);
Point p = new Point(200, 30 * i);
textBox2[i].Location = p;
this.Controls.Add(textBox2[i]);
}
}
private void button1_Click(object sender, EventArgs e)
{
}
You need to read about classes fields and properties
private TextBox[] textBox1;
private TextBox[] textBox2;;
...
public EnterColsAndRows(int width, int height)
{
...
textBox1 = new TextBox[width_of_nonogram];
textBox2 = new TextBox[height_of_nonogram];
...
}
private void button1_Click(object sender, EventArgs e)
{
if(textBox1 != null && textBox1.Length > 0)
{
textBox1[0].Text = "Awesome, i am"
}
}
Further reading
Classes (C# Programming Guide)
Fields (C# Programming Guide)
To access textbox array what you can do is :
foreach (Control x in this.Controls)
{
if (x is TextBox)
{
var textbox = ((TextBox)x);//Your code goes here.
}
}
With this you will be able to access all the textboxes, what you can do is assign name to the textboxes in the EnterColsAndRows function and use it in the above code.

c# Dynamic panel on mouse

I am making a N*M size SUDOKU game. Every number are on a button.
When the program start all button is empty and I would like if I click to a button it is make a little panel on it with buttons for each number to choose one.
private void adatB_Click(object sender, EventArgs e)
{
Button button = sender as Button;
int[] hely = button.Tag.ToString().Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(Int32.Parse).ToArray();
Panel szamok = new Panel
{
Location = MousePosition,
Size = new Size(100, 100)
};
Controls.Add(szamok);
TableLayoutPanel minitabla = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = szorzat,
RowCount = szorzat,
};
for (int i = 0; i < szorzat; i++)
{
minitabla.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
minitabla.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
}
szamok.Controls.Add(minitabla);
Button[,] szamokB = new Button[meret[0], meret[1]];
int d = 1;
for (int i = 0; i < meret[0]; i++)
{
for (int j = 0; j < meret[1]; j++)
{
szamokB[i, j] = new Button();
szamokB[i, j].Tag= hely[0]+","+hely[1];
szamokB[i, j].Text = d.ToString();
szamokB[i, j].Dock = DockStyle.Fill;
szamokB[i, j].Click += szamokB_Click;
minitabla.Controls.Add(szamokB[i, j], i, j);
d++;
}
}
}
private void szamokB_Click(object sender, EventArgs e)
{
Button button = sender as Button;
int[] hely = button.Tag.ToString().Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(Int32.Parse).ToArray();
adatB[hely[0], hely[1]].Text = button.Text;
}
The problem with it when I click a button the pane isn't created.
meret[0] variable is the N, meret[1] is M, adatB is the arry of buttons with the positons in tag.
And If I choosed the number how can I close that panel?
First of all, you should calculate the mouseposition correctly.
From MSDN:
Gets the position of the mouse cursor in screen coordinates.
You should use something like this:
Location = new Point(MousePosition.X - this.Location.X, MousePosition.Y - this.Location.Y)
You will probably need this, to bring your panel to the front:
Controls.Add(szamok);
szamok.BringToFront();
To close the panel you can store the chooser panel and you can remove it from the controls later, use something like this:
public partial class Form1 : Form
{
private Panel myPanel = null;
private void adatB_Click(object sender, EventArgs e)
{
...
Panel szamok = new Panel
{
Location = new Point(MousePosition.X - this.Location.X, MousePosition.Y - this.Location.Y),
Size = new Size(100, 100)
};
if (this.myPanel != null)
{
this.Controls.Remove(this.myPanel);
}
this.myPanel = szamok;
Controls.Add(szamok);
szamok.BringToFront();
...
}
private void szamokB_Click(object sender, EventArgs e)
{
if (this.myPanel != null)
{
this.Controls.Remove(this.myPanel);
this.myPanel = null;
}
...
}
}

Export dynamic label text to Excel

I have a small program that generates a few dynamic labels in a flowLayoutPanel1 I ma trying to export these labels' text to Excel but all I get is the value of the last label.
This is my Export class:
class Export
{
public Export(bool defaultBackgroundIsWhite)
{
this.defaultBackgroundIsWhite = defaultBackgroundIsWhite;
app = new Application();
app.Visible = true;
workbook = app.Workbooks.Add(1);
worksheet = (Worksheet)workbook.Sheets[1];
}
public void Do(string excelName, System.Windows.Forms.Label names)
{
for (int i = 0; i <= 5; i++)
{
AddNames(i,0,names);
}
}
private void AddNames(int row, int col, System.Windows.Forms.Label lbls)
{
if (lbls == null) return;
row++;
col++;
Range range = worksheet.Cells[row + 2, col + 2];
range.NumberFormat = "";
worksheet.Cells[row + 2, col + 2] = lbls.Text;
row--;
col--;
}
private Application app = null;
private Workbook workbook = null;
private Worksheet worksheet = null;
private bool defaultBackgroundIsWhite;
}
The form class code:
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
create();
}
Label lbl;
private void create()
{
flowLayoutPanel1.Controls.Clear();
//int length = ds.Tables[0].Rows.Count;
for (int i = 0; i < 5; i++)
{
lbl = new Label();
lbl.Name = i.ToString();
lbl.Text = "Label "+i;
lbl.Font = new Font(FontFamily.GenericSansSerif, 10, FontStyle.Regular);
lbl.SetBounds(0, 20, 100, 25);
lbl.BorderStyle = BorderStyle.FixedSingle;
flowLayoutPanel1.Controls.Add(lbl);
}
}
private void button1_Click(object sender, EventArgs e)
{
Export ep = new Export(true);
ep.Do("test.xsl", lbl);
}
My Results:
You are always adding the text of the last created label because you are only passing its reference. You should instead pass the List with references of all the labels which Text properties you would like to export to Excel. Change these methods:
List<Label> lbls;
private void create()
{
flowLayoutPanel1.Controls.Clear();
//int length = ds.Tables[0].Rows.Count;
lbls = new List<Labels>();
for (int i = 0; i < 5; i++)
{
Label lbl = new Label();
lbl.Name = i.ToString();
lbl.Text = "Label "+i;
lbl.Font = new Font(FontFamily.GenericSansSerif, 10, FontStyle.Regular);
lbl.SetBounds(0, 20, 100, 25);
lbl.BorderStyle = BorderStyle.FixedSingle;
flowLayoutPanel1.Controls.Add(lbl);
lbls.Add(lbl);
}
}
Also change the method Do in the Export class to accept the List<Label> instead Label:
public void Do(string excelName, List<Label> names)
{
for (int i = 0; i <= names.Count; i++)
{
AddNames(i,0,names[i]);
}
}
List<Label> lbls = new List<Label>();
private void create()
{
flowLayoutPanel1.Controls.Clear();
//int length = ds.Tables[0].Rows.Count;
for (int i = 0; i < 5; i++)
{
lbl = new Label();
lbl.Name = i.ToString();
lbl.Text = "Label "+i;
lbl.Font = new Font(FontFamily.GenericSansSerif, 10, FontStyle.Regular);
lbl.SetBounds(0, 20, 100, 25);
lbl.BorderStyle = BorderStyle.FixedSingle;
lbls.Add(lbl); //< -- add the label to the local list of Labels
flowLayoutPanel1.Controls.Add(lbl);
}
}
private void button1_Click(object sender, EventArgs e)
{
int i = 0;
Export ep = new Export(true);
foreach(var lbl in lbls)
{
i++;
ep.AddNames(i,0,lbl);
}
}
public void AddNames(int row, int col, System.Windows.Forms.Label lbl)
{
if (lbl == null) return;
row++;
col++;
Range range = worksheet.Cells[row + 2, col + 2];
range.NumberFormat = "";
worksheet.Cells[row + 2, col + 2] = lbl.Text;
row--;
col--;
}
You're constructing a new label every time around the for loop in the create() method, and assigning that label to the same field (lbl). By the time you're done, lbl is the last label you created. You could instead add the labels to a List, or pass flowLayoutPanel1.Controls to the go() method, if you can be certain that will contain only the labels you wish to export.
It's a bit clunky TBH, and depending so heavily on the mechanics of the UI like that is not recommended - you'd be far better of with a well thought out model to which your UI is data bound, but if you want to just get it done, that's your problem.

Disabling a dynamic button

Hi I have a small winforms program that will soon develop into something more. The program has 2 panels panel1 and panel2 these panels are populated dynamically with some form controls. the first panel is populated with combo-boxes and the second with a grid of buttons. What I want to achieve is to be able to disable the right button depending on what the user selects from the combobox. Each column of the grid represent a day of the week and the combobox will be used to disable the wanted day by selecting it from the list if you like.
To do this statically is straight forward, however my program will soon expand so that it can handle a large database so that's why I am doing this dynamically. Basically this is where I'm stuck at the moment I want to simply disable the right button.
Below is the interface that i have so far:
And this is my code if any help:
public Form1()
{
InitializeComponent();
}
Button[] btn = new Button[2];
ComboBox[] cmb = new ComboBox[1];
private void Form1_Load(object sender, EventArgs e)
{
placeRows();
}
public void createColumns(int s)
{
for (int i = 0; i < btn.Length; ++i)
{
btn[i] = new Button();
btn[i].SetBounds(40 * i, s, 35, 35);
btn[i].Text = Convert.ToString(i);
panel1.Controls.Add(btn[i]);
}
for (int i = 0; i < cmb.Length; ++i)
{
cmb[i] = new ComboBox();
cmb[i].SelectedIndexChanged += new EventHandler(cmb_SelectedIndexChanged);
cmb[i].Text = "Disable";
cmb[i].Items.Add("Monday");
cmb[i].Items.Add("Tuesday");
cmb[i].SetBounds(40 * i, s, 70, 70);
panel2.Controls.Add(cmb[i]);
}
}
void cmb_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox senderCmb = (ComboBox)sender;
if (senderCmb.SelectedIndex == 1)
{
//MessageBox.Show("Tuesday");
btn[1].Enabled = false;
}
}
public void placeRows()
{
for (int i = 0; i < 80; i = i + 40)
{
createColumns(i);
}
}
}
Alternative 1
Every control has a Tag property.
You can set the Tag property of your buttons to represent the column they are in.
When a selection is made in the combo box, simply search through all buttons, and enable or disable the button based on whether each button's Tag property matches the selected text in the combo box.
Alternative 2
Create a
Dictionary<string, List<Button>> buttonMap;
where the key is the value representing the column ("Tuesday") and the value is a list of buttons with that tag. When creating the buttons initially, also populate that dictionary.
If you go with Alternative 2, you'll have to remember the previously selected value of the checkbox so you can re-enable buttons that are no longer disabled.
If you have lots of buttons, you may find that Alternative 2 is noticeably faster.
UPDATE
Here's a complete working sample of Alternative 1.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
const int ROWS = 2;
const int COLS = 2;
Button[,] btn = new Button[ROWS,COLS];
ComboBox[] cmb = new ComboBox[ROWS];
private void Form1_Load(object sender, EventArgs e)
{
placeRows();
}
private readonly string[] cbTexts = new string[] { "Monday", "Tuesday" };
public void createColumns(int rowIndex)
{
int s = rowIndex * 40;
// Your original code kept overwriting btn[i] for each column. You need a 2-D array
// indexed by the row and column
for (int colIndex = 0; colIndex < COLS; colIndex++)
{
btn[rowIndex, colIndex] = new Button();
btn[rowIndex, colIndex].SetBounds(40 * colIndex, s, 35, 35);
btn[rowIndex, colIndex].Text = Convert.ToString(colIndex);
btn[rowIndex, colIndex].Tag = cbTexts[colIndex];
panel1.Controls.Add(btn[rowIndex, colIndex]);
}
cmb[rowIndex] = new ComboBox();
cmb[rowIndex].SelectedIndexChanged += new EventHandler(cmb_SelectedIndexChanged);
cmb[rowIndex].Text = "Disable";
foreach (string cbText in cbTexts)
{
cmb[rowIndex].Items.Add(cbText);
}
cmb[rowIndex].SetBounds(40, s, 70, 70);
cmb[rowIndex].Tag = rowIndex; // Store the row index so we know which buttons to affect
panel2.Controls.Add(cmb[rowIndex]);
}
void cmb_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox senderCmb = (ComboBox)sender;
int row = (int)senderCmb.Tag;
for (int col = 0; col < COLS; col++)
{
Button b = btn[row, col];
// These three lines can be combined to one. I broke it out
// just to highlight what is happening.
string text = ((string)b.Tag);
bool match = text == senderCmb.SelectedItem.ToString();
b.Enabled = match;
}
}
public void placeRows()
{
for (int rowIndex = 0; rowIndex < 2; rowIndex++)
{
createColumns(rowIndex);
}
}
}

Categories