Dynamically adding controls and eventhandlers (asp.net c#) - c#

I'm a computing foundation year student and am designing a basic e-commerce site for a project at uni and have run into a problem that has me banging my head against my desk
So..
I am dynamically creating a shopping basket using asp.net controls in the Page_Load method of the basket page based off what is in a session variable (type dictionary - the key is the product id and the value is the qty).
I can add items from the browse page which has more dynamically added controls based off whatever the user puts in the products table of the database, that works fine.
I can populate the basket with all the details but am struggling with a '-' and '+' button to alter the qty in the basket.
I can assign the event handler to run a method in a class that adds (or removes) 1 item at a time but the problem I face is if I place my code in Page_Load the function works but renders the controls before the event handler fires (so while the dictionary updates, it's not showing the new value - you have to refresh or add another and then you're always 1 behind)
If I place the code in PreRender the event handler doesnt fire.
This is my first ever project in ASP.NET so please go easy on me if I'm barking up the wrong tree with my methodology.
Any ideas or a nudge in the right direction would be gratefully received
Many thanks in advance
EDIT To add a bit more detail
//creating my button
Button tdQtyDownButton = new Button();
tdQtyDownButton.ID = "qtyDown"+ row["prod_id"]; tdQtyDownButton.Text = "-";
tdQtyDownButton.Click += delegate (object sender1, EventArgs e1) {
ShoppingBasket.AddItem((int)row["prod_id"]); };
tdQtyDown.Controls.Add(tdQtyDownButton);
//in seperate ShoppingBasket class file
public static void AddItem(int prod_id)
{
if (HttpContext.Current.Session["basket"] != null)
{
if(!((Dictionary<int, int>)HttpContext.Current.Session["basket"]).ContainsKey(prod_id))
{
((Dictionary<int, int>)HttpContext.Current.Session["basket"]).Add(prod_id, 1);
}
else
{
int currentQty = 0;
((Dictionary<int, int>)HttpContext.Current.Session["basket"]).TryGetValue(prod_id, out currentQty);
((Dictionary<int, int>)HttpContext.Current.Session["basket"]).Remove(prod_id);
((Dictionary<int, int>)HttpContext.Current.Session["basket"]).Add(prod_id, currentQty + 1);
}
}
else
{
CreateBasket();
AddItem( prod_id);
}
}
As i said, it sort of works - I think it's a just a lifecycle issue and probably needs a wholly fresh approach

Assuming you want to add a Button dynamically and handle it's click event :
Button button1 = new Button();
button1.Text = "dynamic button";
button1.Left = 10; button1.Top = 10;
textBox1.Click += new EventHandler(btn_click);
this.Controls.Add(button1);
private void btn_click()
{
}
Update : From your comment,it seems like that you want to refresh your page without reloading it...For that,your easiest approach will be SignalR or you can use the UpdatePanel Control

For Windows Form Application
public partial class Form1 : Form
{
int i = 1;
int j = 1;
int rbCount = 0;
public Form1()
{
InitializeComponent();
}
private void buttonAddRadio_Click(object sender, EventArgs e)
{
RadioButton rb = new RadioButton();
rb.Name = "Radio Button" + i.ToString();
rb.Text = "Radio Button" + i;
rb.Left = 8;
rb.Top = 15 + (rbCount * 27);
rb.AutoSize = true;
rb.Click += new EventHandler(radio_click);
groupBox1.Controls.Add(rb);
i++;
rbCount++;
}
void radio_click(object sender, EventArgs e)
{
MessageBox.Show(((RadioButton)sender).Text);
}
private void buttonAddCheck_Click(object sender, EventArgs e)
{
CheckBox cb = new CheckBox();
cb.Name = "CheckBox" + j.ToString();
cb.Text = "CheckBox" + j;
cb.Left = 8;
cb.Top = 15 + (rbCount * 27);
cb.AutoSize = true;
cb.Click += new EventHandler(checkbox_checked);
groupBox1.Controls.Add(cb);
j++;
rbCount++;
}
void checkbox_checked(object sender, EventArgs e)
{
MessageBox.Show(((CheckBox)sender).Text);
}
}
For ASP.NET Web Application
string[] myArray = new string[] { "Alex", "Bob", "John", "Srinivas", "Zamal", "Rahul" }
foreach (string item in myArray)
{
HyperLink myHyp = new HyperLink();
myHyp.Text = Suspect;
myHyp.NavigateUrl = "User Details.aspx?name=" + HttpUtility.UrlEncode(item));
myPanel.Controls.Add(new LiteralControl("<ul>"));
myPanel.Controls.Add(new LiteralControl("<li>"));
myPanel.Controls.Add(hpSuspect);
myPanel.Controls.Add(new LiteralControl("</li>"));
myPanel.Controls.Add(new LiteralControl("</ul>"));
}
N.B. LiteralControl is used for adding general HTML controls.

Related

UWP C# How To Handle Event for Dynamically Created Button(s) and Control

in relation to the post UWP C# Add Button Dynamically and Organizing On StackPanel I have additional questions
how do I control these dynamically created button(s)' event? eg. button 1 to turns on LED 1, button 2 to turns on LED 2 etc.
how to selectively remove the button(s) and reorganize the remaining buttons with no empty spaces in between.
Thank you.
Update:
I have a routine to add the client with details such as client IP etc. from the client and to add and display them in a scrollviewer.
How do i link either the clientname or client ip to the dictionary?
private async void AddClientList()
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
ClientListUserControl clientListControl = new ClientListUserControl(this, new ClientList(clientName, receiveIP, DateTime.Now, receivePort, receiveService, receiveDEV, receiveSTS, receiveACT));
ClientList_Panel.Children.Add(clientListControl);
clientListControl.updateDisplay();
});
}
You can also use Tag property of Button to pass the parameter. This property is inherited from FrameworkElement, and generally it is used to get or set an arbitrary object value that can be used to store custom information about this object.
Please refer to following code.
private void ButtonCreateNewButton_Click(object sender, RoutedEventArgs e)
{
Button b = new Button();
b.Height = 30;
b.Width = 100;
b.VerticalAlignment = VerticalAlignment.Top;
b.HorizontalAlignment = HorizontalAlignment.Left;
b.Margin = new Thickness(6, 6, 6, 6);
b.Content = "Button " + buttonCounter;
b.Tag = "LED-" + buttonCounter;
b.Click += Button_Click;
....
buttonCounter++;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var btn = sender as Button;
var led = btn.Tag;
//use led_name as a parameter here, according with this variable to turn on the LED
TurnOnOffLed(led);
}
To your first question:
To handle this, you should introduce a dictionary, where the button is the key and your value is the client. So you can get the linked client in the ClickHandler.
public Dictionary<Button, object> clientDict = new Dictionary<Button, object>();
Note: Here the type of the client is object, because I don`t know what type you have!
You add the button inside of your AddButton routine. Again: I dont know where you get your client from, so I added the value null. Change this to fulfil your requirements. Then you add another ClickHandler and get the linked client:
b.Click += HandleButtonClick;
clientDict.Add(b, null);
private void HandleButtonClick(object sender, RoutedEventArgs e)
{
//Execute whatever you want from your client:
var client = clientDict[sender as Button];
}
To your second question:
You need to add a RemoveMethod, where you get the column and row of the button, which should be deleted. Afterwards you can manipulate all other buttons column and row property. To avoid, that a new added button is not aligned to the others, you need to change the add-process, to make the position of the new button depending on the number of elements in your dictionary. Here an example how the full code could look like:
public int buttonCounter = 1;
public Dictionary<Button, object> clientDict = new Dictionary<Button, object>();
private void RemoveBtn(Button button)
{
var row = Grid.GetRow(button);
var column = Grid.GetColumn(button);
//Rearange
foreach (var btn in clientDict.Keys)
{
var r = Grid.GetRow(btn);
var c = Grid.GetColumn(btn);
if (c > column || (c == column && r > row))
{
if (r != 0)
{
//Set the row new
Grid.SetRow(btn, r - 1);
}
else
{
//Need to set it to a new column
Grid.SetRow(btn, 3);
Grid.SetColumn(btn, c - 1);
}
}
}
myGrid.Children.Remove(button);
clientDict.Remove(button);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//Create the button
Button b = new Button();
b.Height = 30;
b.Width = 100;
b.VerticalAlignment = VerticalAlignment.Top;
b.HorizontalAlignment = HorizontalAlignment.Left;
b.Margin = new Thickness(20, 20, 0, 0);
b.Content = "Button " + buttonCounter;
b.Click += HandleButtonClick;
clientDict.Add(b, null);
//Calculate the place of the button
int column = (int)(clientDict.Count / 4);
int row = clientDict.Count % 4;
//Check if you need to add a columns
if (row == 0 && myGrid.ColumnDefinitions.Count <= column)
{
ColumnDefinition col = new ColumnDefinition();
col.Width = new GridLength(column, GridUnitType.Auto);
myGrid.ColumnDefinitions.Add(col);
}
//Add the button
myGrid.Children.Add(b);
Grid.SetColumn(b, column);
Grid.SetRow(b, row);
buttonCounter++;
}
private void HandleButtonClick(object sender, RoutedEventArgs e)
{
//Execute whatever you want from you handler:
var client = clientDict[sender as Button];
}
Note: The rearrange process is not performance optimized.

How can I retrieve the input values of dynamically created textfields?

Here is my code so far where I have a numericupdown item named numericUpDown and button. Once the user selects a number when they press the button it dynamically created the fields.
private void createPerson_Click(object sender, EventArgs e)
{
Label[] person_Name = new Label[(int)this.numericUpDown.Value];
TextBox[] person_txtinput = new TextBox[(int)this.numericUpDown.Value];
for (int i = 0; i < this.numericUpDown.Value; i++)
{
//create person name label
Person_Name[i] = new Label();
Person_Name[i].Location = new System.Drawing.Point(20, 114 + i * 25);
Person_Name[i].Size = new System.Drawing.Size(120, 15);
Person_Name[i].Text = (i + 1).ToString() + #")" + "Person Name:";
this.Controls.Add(Person_Name[i]);
//create person name textbox
PersonNameTxtInput[i] = new TextBox();
PersonNameTxtInput[i].Location = new System.Drawing.Point(140, 114 + i * 25);
PersonNameTxtInput[i].Size = new System.Drawing.Size(125, 20);
this.Controls.Add(PersonNameTxtInput[i]);
}
}
private void save_Click(object sender, EventArgs e)
{
for (int i = 0; j < this.numericUpDown.Value; i++)
{
MessageBox.Show("" + PersonNameTxtInput[i].Text);
}
}
My question is, how can I get all the values from the textboxes depending on how many fields are created by the user when the save button is pressed?
I have tried using the code within the save button listener however how can i make Label[] person_Name = new Label[(int)this.numericUpDown.Value]; a global variable so i can access it within the save button for loop.
Well, I don't know exactly why you are doing this in this particular way and I must admit it doesn't seem very effective, but you could just do what Ryan_L suggested and iterate through this.Controls like this
for(int i = 0; i < this.Controls.Count; i++)
{
if(this.Controls[i] is TextBox) //skip buttons and labels
{
MessageBox.Show("" + this.Controls[i].Text);
}
}
Now, regarding your question how to define a global variable so you can access it within the save button for loop...just define the two arrays outside of the createPerson_Click event like this:
Label[] person_Name;
TextBox[] person_txtinput;
private void button1_Click(object sender, EventArgs e)
{
person_Name = new Label[(int)this.numericUpDown.Value];
person_txtinput = new TextBox[(int)this.numericUpDown.Value];
//the rest of the code
}
Hope this helps. However, you might want to reconsider your entire approach.

How do I add click events to all buttons that have names starting with a certain string in C#?

I am writing a simple calculator script for my C# programming class. It will of course have buttons 0-9 that will update the output textbox to add the number of whatever button is clicked. My problem right now that is I would rather not have to have 10 different click events in my script. I would rather have a loop that cycles through the buttons that will add the same click event to each one and then decide what number to add to the output based on the button.
So right now, I have a click event for the "1" button which is this...
private void btnNum1_Click(object sender, EventArgs e)
{
txtOutput.Text = Convert.ToString(txtOutput.Text + "1");
}
This works fine, but, again, I would rather not have to do this 10 times. How can I create a loop that prevents this?
The button names are btnNum1, btnNum2, btnNum3, etc.
Assuming the button text is just "1", "2" etc you could do this:
private void btnNum_Click(object sender, EventArgs e)
{
var button = sender as Button
txtOutput.Text += button.Content.ToString();
}
Then just apply this event to all the buttons.
Also note you don't need Convert.ToString() as what you are trying to convert is already a string. Using += also cleans up your code a bit.
You could do this to wire-up all of the events in one go:
for (var n = 0; n <= 9; n++)
{
var btn =
this
.Controls
.Find("btnNum" + n.ToString(), false)
.Cast<Button>()
.First();
var digit = n;
btn.Click += (s, e) =>
{
txtOutput.Text = digit.ToString();
};
}
You could enumerate the children controls of your Form/Control, look the type of controls which are type of Button and the name StartWith 'btnNum', with each of these buttons, add a Click event address to btnNum_Click().
Say if all your buttons are contained in a Panel named 'pnlButtons', you could loop all the children like this.
foreach (var control in pnlButtons.Controls)
{
if(control.GetType() == typeof(Button))
{
var button = control as Button;
if (button .Name.StartWith('btnNum'))
{
button.Click += btnNum_Click;
}
}
}
You can use the "Tag" property of the Button control and make an array of Buttons to subscribe to the same event. See sample below:
void InitializeButtons()
{
Button btnNum1 = new Button();
btnNum1.Text = "1";
btnNum1.Tag = 1;
//Button 2..8 goes here
Button btnNum9 = new Button();
btnNum9.Text = "9";
btnNum9.Tag = 9;
Button[] buttons = new Button[]{
btnNum1, btnNum2, btnNum3, btnNum4, btnNum5, btnNum6, btnNum7, btnNum8, btnNum9
};
for (int i = 0; i < buttons.Length; i++)
{
buttons[i].Click += Button_Click;
}
}
void Button_Click(object sender, EventArgs e)
{
Button button = (Button)sender;
int value = (int)button.Tag;
//Do something with value
}
Assuming WinForms, you can recursively search for buttons that start with "btnNum" and wire them up to a common handler like this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Load += Form1_Load;
}
void Form1_Load(object sender, EventArgs e)
{
FindButtons(this);
}
private void FindButtons(Control ctl)
{
foreach(Control ctrl in ctl.Controls)
{
if (ctrl.Name.StartsWith("btnNum") && (ctrl is Button))
{
Button btn = (Button)ctrl;
btn.Click += btn_Click;
}
else if(ctrl.HasChildren)
{
FindButtons(ctrl);
}
}
}
private void btn_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
txtOutput.Text = Convert.ToString(txtOutput.Text + btn.Text);
}
}

How to access or modify dynamically created button

I've created 8*8 arrays of button to create a grid for Minesweeper Game. After creating the grid I need to access them(buttons). How can I access them like change the name or disable click-ability or change the colors.
private void gridDesign()
{
/***********************************Uniform grid*********************/
int firstLoop, secondLoop;
for (firstLoop = 0; firstLoop < 8; firstLoop++)
{
for (secondLoop = 0; secondLoop < 8; secondLoop++)
{
Button lbl = new Button()
{
Name = "_" + firstLoop.ToString() +"_"+ secondLoop.ToString(),
Content = firstLoop.ToString() + " " + secondLoop.ToString(),
};
lbl.Click += button_Click;
uniformgridMinesweeper.Children.Add(lbl);
}
}
/********************************************************************/
}
private void button_Click(object sender, RoutedEventArgs e)
{
Button bbb = e.Source as Button;
bbb.Background = Brushes.Indigo;
//how can i access a button named "_5_5"
}
It is straightforward to access a child of a Grid with a specific property (Name):
var button = uniformgridMinesweeper.Children.OfType<Button>()
.FirstOrDefault(button => button.Name == "_5_5");
That said, you might want to take thumbmunkey's advice and put the buttons in your own Dictionary or lookup for quick and easy access. Or better yet, use data binding with a view model ...

Removing TextBoxes created Dynamically on Button click

I have tried creating textboxes dynamically using lists. All i need now is, how can i reset all text boxes that i have created by hitting a reset button.
The following is my code:
public void button2_Click_1(object sender, EventArgs e)
{
int number = Convert.ToInt32(textBox2.Text);
List<TextBox> inputTextBoxes;
inputTextBoxes = new List<TextBox>();
for (int i = 1; i <= number; i++)
{
Label labelInput = new Label();
TextBox textBoxNewInput = new TextBox();
labelInput.Text = "Activity No: " + i;
labelInput.Location = new System.Drawing.Point(30, textBox2.Bottom + (i * 40));
labelInput.AutoSize = true;
textBoxNewInput.Location = new System.Drawing.Point(labelInput.Width+60, labelInput.Top - 3);
inputTextBoxes.Add(textBoxNewInput);
this.Controls.Add(labelInput);
this.Controls.Add(textBoxNewInput);
}
}
The answer is:
private void resetButton_Click(object sender,EventArgs e)
{
for (int i = 0; i <= inputTextBoxes.Length; i++)
{
inputTextBoxes[i].Text = "";
}
}
And you should declare inputTextBoxes is a class member which is same class' of buttons.
Move the following line outside the event handler function (outside the function but inside the class)
List<TextBox> inputTextBoxes;
Then on the reset button click
private void btnReset_Click(object sender, EventArgs e)
{
foreach(TextBox txt in inputTextBoxes)
{
this.Controls.Remove(txt);
}
inputTextBoxes.Clear();
}
Edit: Corrected the class type in foreach loop (from Button to TextBox)

Categories

Resources