I am new to C# and programming in general. I was trying to make a simple shopping list app using a windows form application and Visual studio. This is how I am adding items to the list.
public Form1()
{
InitializeComponent();
}
int x = 50;
int y = 58;
private void addButton_Click(object sender, EventArgs e)
{
Label itemName = new Label();
itemName.Text = itemInput.Text;
itemInput.Text = "";
this.Controls.Add(itemName);
itemName.Location = new Point(x, y);
itemName.Width = 260;
CheckBox coupon = new CheckBox();
coupon.Location = new Point(x - 30, y);
this.Controls.Add(coupon);
y = y + 25;
}
The main issue I have is that I can't have another event change the properties of the label. EX:
public Form1()
{
InitializeComponent();
}
int x = 50;
int y = 58;
private void addButton_Click(object sender, EventArgs e)
{
Label itemName = new Label();
itemName.Text = itemInput.Text;
itemInput.Text = "";
this.Controls.Add(itemName);
itemName.Location = new Point(x, y);
itemName.Width = 260;
CheckBox coupon = new CheckBox();
coupon.Location = new Point(x - 30, y);
this.Controls.Add(coupon);
Button deletButton = new Button();
deletButton.Text = "delete";
this.Controls.Add(deletButton);
deletButton.Location = new Point(x + 260, y);
deletButton.Width = 50;
y = y + 25;
}
private void deletButton_Click(object sender, EventArgs e)
{
itemName.Text = "";
}
It says
the name itemName does not exist in the current context
which make sense because it is in a different method.
My main question is, can I make itemName available outside of that method? Or am I totally going about this wrong and have to redesign the program for the ground up?
Let's say that you want to stick with the dynamic addition of controls, as you're doing now, then a simple way is to give it a name and the find it by that name:
// When you're creating it.
itemName.Name = "itemName";
// Finding it.
var itemName = (Label)this.Controls["itemName"];
// Another way to find it.
var itemName = (Label)this.Controls.Find("itemName", true);
Related
I have an add user button which dynamically adds a remove button and a username textbox when the user clicks it. The user can click the button as many times as they like and the controls will continue to add.
I am having trouble with the remove button that is created dynamically. It should removed the itself and the username textbox next to it. Instead it will always remove the top row that was added. Also when you click add a new user after you have clicked remove it doesn't automatically fill the blank space - it moves the new textbox and button to the bottom line.
Here is my code:
private void AddUserbtn_Click_1(object sender, EventArgs e)
{
TextBox[] Username = new TextBox[n];
Button[] Remove = new Button[n];
int UsernameX, UsernameY, RemoveX, RemoveY;
UsernameX = 346;
UsernameY = 45;
RemoveX = 946;
RemoveY = 45;
for (int i = 0; i < n; i++)
{
Username[i] = new TextBox();
Username[i].Size = new Size(233, 26);
Username[i].Location = new Point(UsernameX, UsernameY + space);
Username[i].Font = new Font("Arial", 10);
Username[i].Name = "Username" ;
Remove[i] = new Button();
Remove[i].Location = new Point(RemoveX, RemoveY + space);
Remove[i].Text = "Remove";
Remove[i].Font = new Font("Arial", 10);
Remove[i].Size = new Size(95, 23);
Remove[i].UseVisualStyleBackColor = true;
Remove[i].Click += new EventHandler(Remove_Click);
Remove[i].Name = "Remove";
space += 35;
}
for (int i = 0; i < n; i++)
{
CaeUsersPanel.Controls.Add(Username[i]);
CaeUsersPanel.Controls.Add(Remove[i]);
}
}
private void Remove_Click(object sender, EventArgs e)
{
CaeUsersPanel.Controls.Remove(CaeUsersPanel.Controls[("Username")]);
CaeUsersPanel.Controls.Remove(CaeUsersPanel.Controls[("Remove")]);
}
Put a class variant to store Button - TextBox pair, and delete respectively. Quick tested code below - not fine tuned for memory leak / logic etc, just a sample code that fulfills your requirement.
Dictionary<Button, TextBox> pair = new Dictionary<Button, TextBox>(); // A dictionary to store the Button - TextBox pair
private void button1_Click(object sender, EventArgs e) {
int n = 3; // Added for testing
int space = 0; // Added for testing
int UsernameX, UsernameY, RemoveX, RemoveY;
UsernameX = 100; // Modified for testing
UsernameY = 45;
RemoveX = 400; // Modified for testing
RemoveY = 45;
for (int i = 0; i < n; i++) {
var Username = new TextBox();
Username.Size = new Size(233, 26);
Username.Location = new Point(UsernameX, UsernameY + space);
Username.Font = new Font("Arial", 10);
Username.Name = "Username";
var Remove = new Button();
Remove.Location = new Point(RemoveX, RemoveY + space);
Remove.Text = "Remove";
Remove.Font = new Font("Arial", 10);
Remove.Size = new Size(95, 23);
Remove.UseVisualStyleBackColor = true;
Remove.Click += new EventHandler(Remove_Click);
Remove.Name = "Remove";
Controls.Add(Username);
Controls.Add(Remove);
pair.Add(Remove, Username);
space += 35;
}
}
private void Remove_Click(object sender, EventArgs e) {
Controls.Remove((Button)sender); // Removes the delete button
Controls.Remove(pair[(Button)sender]); // Removes the textbox
pair.Remove((Button)sender); // Removes the entry in dictionary
}
Update: Another version for better memory and logic matters. Also shifts up the rest of controls up if it's the OP's desire.
int n = 3; // Added for testing, probably you already have it somewhere
int space = 0; // Added for testing, probably you already have it somewhere
// Moved for logic
// Value modified for testing
int UsernameX = 100;
int UsernameY = 45;
int RemoveX = 400;
int RemoveY = 45;
int SpaceDelta = 35; // Added for logic
List<Button> RemoveButtons = new List<Button>();
List<TextBox> UsernameTextBoxes = new List<TextBox>();
private void button1_Click(object sender, EventArgs e) {
Random rnd = new Random((int)DateTime.Now.Ticks); // Added for testing
for (int i = 0; i < n; i++) {
var Username = new TextBox();
Username.Size = new Size(233, 26);
Username.Location = new Point(UsernameX, UsernameY + space);
Username.Font = new Font("Arial", 10);
Username.Name = "Username";
Username.Text = $"{(int)(rnd.NextDouble() * 100000)}"; // Added for testing
var Remove = new Button();
Remove.Location = new Point(RemoveX, RemoveY + space);
Remove.Text = $"{(int)(rnd.NextDouble() * 100000)}"; // Modified for testing
Remove.Font = new Font("Arial", 10);
Remove.Size = new Size(95, 23);
Remove.UseVisualStyleBackColor = true;
Remove.Click += new EventHandler(Remove_Click);
Remove.Name = "Remove";
Controls.Add(Username);
Controls.Add(Remove);
RemoveButtons.Add(Remove);
UsernameTextBoxes.Add(Username);
space += SpaceDelta;
}
}
private void Remove_Click(object sender, EventArgs e) {
int idx = RemoveButtons.IndexOf((Button)sender);
// Remove button
RemoveButtons[idx].Dispose();
RemoveButtons.RemoveAt(idx);
// Remove textbox
UsernameTextBoxes[idx].Dispose();
UsernameTextBoxes.RemoveAt(idx);
// Shift controls up
for (int i = idx; i < RemoveButtons.Count; i ++) {
RemoveButtons[i].Top -= SpaceDelta;
UsernameTextBoxes[i].Top -= SpaceDelta;
}
space -= SpaceDelta;
}
Remove the two last created :
private void Remove_Click(object sender, EventArgs e)
{
this.Controls.Remove(this.Controls[this.Controls.Count - 1]);
this.Controls.Remove(this.Controls[this.Controls.Count - 1]);
}
I have a checkedListBox in a TabControl
What I want is to create a label and NumericUpDown dynamically, when User check an item of checkedListBox it will show the new label and NumericUpDown
Then , when it Unchecked this item ,The numericUpDown will be clear (empty).
Conclusion: As many checked items , as many w've create labels and NumericUpDowns.
Please, how will I do that ??
For each checkbox item in your checkedListBox in properties switch to events and create subscriber checkBoxName_CheckStateChanged for event CheckStateChanged.
The code in the sucriber can be like this:
private void checkBox1_CheckStateChanged(object sender, EventArgs e)
{
var source = sender as CheckBox;
if (source.Checked == true)
{
this.numericUpDown1.Text = "TextWhenChecked";
this.labelAtTheNumericUpDown.Text = "TextWhenChecked";
}
else
{
this.numericUpDown1.Text = "TextWhenUnchecked";
this.label1.Text = "TextWhenUnchecked";
}
}
You fill the strings as you want. These are only examples.
To have only checkBox checked at a time look at here: https://stackoverflow.com/a/24693858/6650581.
What you need to do is creating Label and NumericUpDown manually and show it by adding to Controls collection. A TableLayoutPanel can help you arranging controls without setting Size and calculate Location manually.
Here is an example:
public class MainForm : Form
{
private CheckedListBox checkedListBox;
private TableLayoutPanel tableLayoutPanel;
public MainForm()
{
InitializeComponent();
//Fill checkedListBox and create controls
for( int i = 0; i <= 5; i++ )
{
checkedListBox.Items.Add( i.ToString() );
Label lbl = new Label()
{
Name = "lbl" + i,
Text = "Label " + i,
Visible = false
};
NumericUpDown num = new NumericUpDown()
{
Name = "num" + i,
Value = i,
Visible = false
};
tableLayoutPanel.Controls.Add( lbl, 0, i );
tableLayoutPanel.Controls.Add( num, 1, i );
}
}
private void checkedListBox_ItemCheck( object sender, ItemCheckEventArgs e )
{
if( e.NewValue == CheckState.Checked )
{
tableLayoutPanel.Controls["lbl" + e.Index].Visible = true;
tableLayoutPanel.Controls["num" + e.Index].Visible = true;
}
else
{
tableLayoutPanel.Controls["lbl" + e.Index].Visible = false;
((NumericUpDown)tableLayoutPanel.Controls["num" + e.Index]).Value = 0M;
}
}
private void InitializeComponent()
{
this.checkedListBox = new System.Windows.Forms.CheckedListBox();
this.tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel();
this.SuspendLayout();
//
// checkedListBox
//
this.checkedListBox.Location = new System.Drawing.Point(8, 8);
this.checkedListBox.Name = "checkedListBox";
this.checkedListBox.Size = new System.Drawing.Size(200, 100);
this.checkedListBox.TabIndex = 1;
this.checkedListBox.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(this.checkedListBox_ItemCheck);
//
// tableLayoutPanel
//
this.tableLayoutPanel.AutoScroll = true;
this.tableLayoutPanel.ColumnCount = 2;
this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel.Location = new System.Drawing.Point(8, 112);
this.tableLayoutPanel.Name = "tableLayoutPanel";
this.tableLayoutPanel.Size = new System.Drawing.Size(200, 100);
this.tableLayoutPanel.TabIndex = 2;
//
// MainForm
//
this.ClientSize = new System.Drawing.Size(223, 227);
this.Controls.Add(this.tableLayoutPanel);
this.Controls.Add(this.checkedListBox);
this.Name = "MainForm";
this.ResumeLayout(false);
}
}
How do I make a kind of grid with colours that can be selected and be saved to a field on selection? Like in the chat options in Twitch.
Windows Form provides the ColorDialog
ColorDialog colorDialog = new ColorDialog();
colorDialog.ShowDialog();
The selected Color could be called with:
colorDialog.Color
All you need is TableLayoutPanel and panel for each cell of it:
public partial class MainForm : Form
{
private Color selected_color;
private List<Color> colors;
public MainForm()
{
InitializeComponent();
colors = new List<Color>();
colors.Add(Color.Red);
colors.Add(Color.Green);
colors.Add(Color.Blue);
colors.Add(Color.Yellow);
colors.Add(Color.Teal);
colors.Add(Color.RosyBrown);
colors.Add(Color.Lime);
colors.Add(Color.Gray);
tableLayoutPanel.CellBorderStyle = TableLayoutPanelCellBorderStyle.OutsetDouble;
for (byte i = 0; i < tableLayoutPanel.Controls.Count; i++)
{
Panel p = tableLayoutPanel.Controls[i] as Panel;
p.BackColor = colors[i];
p.Click += panel_click;
}
}
private void panel_click(object sender, EventArgs e)
{
Panel p = sender as Panel;
selected_color = p.BackColor;
lbl_color.Text = selected_color.ToString();
lbl_color.ForeColor = selected_color;
}
private void btn_showMoreColours_Click(object sender, EventArgs e)
{
Panel[] panels = new Panel[4];
for (byte i = 0; i < panels.Length; i++)
{
panels[i] = new Panel();
panels[i].Dock = DockStyle.Fill;
panels[i].Location = new System.Drawing.Point(3, 3);
panels[i].Name = "panel" + (i + 4);
panels[i].Size = new System.Drawing.Size(123, 100);
panels[i].BackColor = colors[i + 4];
panels[i].Click += panel_click;
tableLayoutPanel.Controls.Add(panels[i]);
}
Size = new Size(Size.Width, Size.Height * 2);
}
}
After clicking a cell you will get Color in field selected_color.
EDIT:
A have added show more colours button as well. It will expand like shown below:
Source code here
I have a feeling that Im am missing something obvious but:
I have a single row of pictures in a form, in theory the pictures could go on forever. I need a scroll bar so that the user can look at all of the pictures in the row. I know I need to enable auto scroll but I have no idea how to enable it. Can someone tell me how to enable it or something that I am missing?
If it helps this is the code i am using to generate the pictures:
private void imagePalletToolStripMenuItem_Click(object sender, EventArgs e)
{
MyPalletGui.Show();
Dictionary<string,Bitmap> MyPallet = MyImageCollection.ToDictionary();
int xcor = -50;
int ycor = 0;
foreach (Bitmap curtImage in MyPallet.Values){
PictureBox myPicBox = new PictureBox();
xcor += 50;
myPicBox.Location = new Point(xcor, ycor);
myPicBox.Width = 50;
myPicBox.Height = 50;
myPicBox.Visible = true;
myPicBox.Image = new Bitmap(curtImage);
this.MyPalletGui.Controls.Add(myPicBox);
This code will do exactly what you want, it uses the Form as the ViewPort with AutoScroll:
public Form1()
{
InitializeComponent();
PopulatePictures();
}
private void PopulatePictures()
{
this.AutoScroll = true;
string[] list = Directory.GetFiles(#"C:\\Users\\Public\\Pictures\\Sample Pictures", "*.jpg");
PictureBox[] picturebox= new PictureBox[list.Length];
int y = 100;
for (int index = 0; index < picturebox.Length; index++)
{
picturebox[index] = new PictureBox();
this.Controls.Add(picturebox[index]);
picturebox[index].Location=new Point(index * 120, y);
if(x%12 == 0)
y = y + 150;
picturebox[index].Size = new Size(100,120);
picturebox[index].Image = Image.FromFile(list[index]);
}
}
my panel in my windows form application doesn't include all the buttons i asked it to. It shows only 1 button, Here is the code
private void AddAlphaButtons()
{
char alphaStart = Char.Parse("A");
char alphaEnd = Char.Parse("Z");
for (char i = alphaStart; i <= alphaEnd; i++)
{
string anchorLetter = i.ToString();
Button Buttonx = new Button();
Buttonx.Name = "button " + anchorLetter;
Buttonx.Text = anchorLetter;
Buttonx.BackColor = Color.DarkSlateBlue;
Buttonx.ForeColor = Color.GreenYellow;
Buttonx.Width = 30;
Buttonx.Height = 30;
this.panelButtons.Controls.Add(Buttonx);
//Buttonx.Click += new System.EventHandler(this.MyButton_Click);
}
}
Aren't they all going to be on the same position?
Try setting Buttonx.Location = new Point(100, 200);
(but with different points for different buttons)
You could use a FlowLayoutPanel, which would take care of the layout for you, or you need to track the locations yourself, or which could look something like this:
private void AddAlphaButtons()
{
char alphaStart = Char.Parse("A");
char alphaEnd = Char.Parse("Z");
int x = 0; // used for location info
int y = 0; // used for location info
for (char i = alphaStart; i <= alphaEnd; i++)
{
string anchorLetter = i.ToString();
Button Buttonx = new Button();
Buttonx.Name = "button " + anchorLetter;
Buttonx.Text = anchorLetter;
Buttonx.BackColor = Color.DarkSlateBlue;
Buttonx.ForeColor = Color.GreenYellow;
Buttonx.Width = 30;
Buttonx.Height = 30;
// set button location
Buttonx.Location = new Point(x, y);
x+=30;
if(x > panel1.Width - 30)
{
x = 30;
y+=30;
}
this.panelButtons.Controls.Add(Buttonx);
//Buttonx.Click += new System.EventHandler(this.MyButton_Click);
}
}