Getting values from dynamically generated controls - c#

I am generating wpf form dynamically. All the controls are generated dynamically as follows
A sample code snippet
String tbname = name;
TextBlock txtBlock1 = new TextBlock();
txtBlock1.Text = tbname;
Grid.SetRow(txtBlock1, count);
Grid.SetColumn(txtBlock1, icount);
SampleGrid.Children.Add(txtBlock1);
TextBox txtBox = new TextBox();
txtBox.Text = ptiAttribute.description;
txtBox.Name = tbname.Replace(" ", "");
DynamicGrid.RegisterName(txtBox.Name, txtBox);
Grid.SetRow(txtBox, count);
Grid.SetColumn(txtBox, icount+1);
SampleGrid.Children.Add(txtBox);
Attaching a button click event as follows
var Button = CreateButton("Save", 15, 3);
Button.Click += new RoutedEventHandler(button_Click);
SampleGrid.Children.Add(Button);
I would like to get all the control values (For example: The above text box has value Book), I have to get it after button click. I am not only having text box. I have combo box, date picker too. I don't know which name is registered (RegisterName). Every thing dynamic.
private static void button_Click(object sender, RoutedEventArgs e)
{
# How to get dynamic values here (text bx value, date picker value, combo box value)
}
Simply, how to get values from dynamically generated controls. I have gone through a lot of Visual tree links but I don't know how it works on button click.
Any simple code snippet will help me to move ahead. Thanks

I'm not used to WPF but try this approach(inspired by this):
private static void button_Click(object sender, RoutedEventArgs e)
{
Button btn = (Button)sender;
int row = Grid.GetRow(btn);
TextBox txtBox = SampleGrid.Children
.OfType<TextBox>()
.First(txt => txt.Name == name && Grid.GetRow(txt) == row);
// ...
}

Related

Unable to get dynamically created textbox.text data on button click event using c# and XAML

I'm having trouble getting text from a textbox in c#/xaml. I am running 2 methods - the first which creates a stackpanel and adds 2 textboxes to it and the second is intended to just take the text from the 2 textboxes and assign it to a class object I have defined elsewhere. However - when I try to get the textbox.text, it says it doesn't recognise the variable name I have used for the textbox object. Can anyone offer any clue as to what I'm doing wrong? Here's my code.
public void createstackpanel()
{
StackPanel myStackPanel = new StackPanel();
myStackPanel.Orientation = Windows.UI.Xaml.Controls.Orientation.Vertical;
MyTextBoxTextClass Text1 = new MyTextBoxTextClass ();
TextBox tb1 = new TextBox();
TextBox tb2 = new TextBox();
tb1.Text = "My TextBox 1 Text";
tb2.Text = "My TextBox 2 Text";
myStackPanel.Children.Add(tb1);
myStackPanel.Children.Add(tb2);
}
private void CreateStackPanelButton_Click(object sender, RoutedEventArgs e)
{
//This gets pressed first
createstackpanel();
}
private void SendTextToClass_Click(object sender, RoutedEventArgs e)
{
//This gets pressed second. I have created the StoreMyText class elsewhere and it simply contains 2 properties - textbox1 and textbox2 (both strings)
StoreMyText mytext = new StoreMyText();
mytext.textbox1 = tb1.Text;
mytext.textbox2 = tb2.Text;
}
The issue here is that tb1.Text and tb2.Text aren't being recognised. Why?
Declare
TextBox tb1;
TextBox tb2;
outside the createstackpanel() function in the Class level.
and initialize
tb1 = new TextBox();
tb2 = new TextBox();
inside the createstackpanel() function.
tb1 and tb2 declared in createstackpanel method.
They can't accessed in SendTextToClass_Click method.
P.S. I think it's not doog idea to use dynamically created textboxes in this situation. What is a final goal of your code?
List of textboxes sample:
// class level declaration:
List<TextBox> textboxes = new List<TextBox>();
// createstackpanel method:
textboxes.Add(new TextBox() { Text = "textbox #1" });
textboxes.Add(new TextBox() { Text = "textbox #2" });
// SendTextToClass_Click method:
// some operation with textboxes list

Adding button to panel dynamically and getting it's parent ID

I created a page where I give admin's a way to change photos info (e.g. Title, Description, etc) All the controls on the page are added dynamically because I have more than one gallery of photos.
panel --> parent.
button .
title text box.
description text box.
In every panel, I have button that when clicked, sends the changed information to the server where the photo info is stored (Flickr). The click event for this button is added dynamically, and I want to know if is possible to get the parent of the Button I just clicked on.
Here is the code where I add all my controls:
//global veriables (this is only part of the code)
Panel panel;
Button button;
for (int i = 0; i < photo.Length; i++) {
photo[i] = new FlickerImages(photoSet.MediumURLS[i], photoSet.ThumbnailURLS[i], photoSet.Titles[i], photoSet.Descreption[i]);
panel = new Panel();
panel.ID = "panel" + i;
button = new Button();
button.ID = "sendDataButton" + i;
button.Text = "send data";
button.Click += button_Click; //adding the event
label = new Label();
label.ID = "editLabel" + i;
panel.Controls.Add(label);
panel.Controls.Add(photo[i].CurrentImage(i)); //Image control
panel.Controls.Add(photo[i].EditTitleTextBox(i)); //TextBox control
panel.Controls.Add(photo[i].EditCommentTextBox(i)); //TextBox control
panel.Controls.Add(button);
Form.Controls.Add(panel);
}
Here is the click event I add to all the buttons:
void button_Click(object obj, EventArgs e) {
Response.Write(button.Parent.ID); // i get panel10 every time this get fired.
}
I know this is possible with jQuery but is it possible to get the button ID in ASP.NET?
Sorry for my English and thanks for the help.
Not sure, but are you looking for the ClientID property? (button.Parent.ClientID)
Edit:
You should reference the sending button in the event handler:
void button_Click(object obj, EventArgs e)
{
Response.Write(((Button)obj).Parent.ID);
}

Data binding to list and dynamically adding controls using Windows Forms

I have a List<Appointment> where an Appointment is.
public class Appointment
{
public string Title { get; set; }
public string Start { get; set; }
public string End { get; set; }
}
I want to dynamically add each list item on a separate line on the form like so:
item.Title + " between" + item.Start + " and " + item.End;
I want to be able to click each item (the text), then with each click it can toggle the colour of the text between red and black (that is, if black it turns red, if red it turns black when you click).
I come from a web background, but I am just struggling with Windows Forms data binding. I've tried with table layout panel but just don't know where to begin with changing the color of an item on click.
PS: If it helps, the number of items in the list will probably not be more than 10.
I've gotten a bit further as per Jamie Ide's comment:
var appts = GetAllCalendarItems();
foreach (var item in appts)
{
Label label = new Label();
label.Text = item.Title + " between" + item.Start + " and " + item.End;
label.Click += new EventHandler(label_Click);
flowLayoutPanel1.Controls.Add(label);
}
...
private void label_Click(object sender, EventArgs e)
{
// This is wrong - what goes here??
((Label)sender).ForeColor = Color.Red;
}
Dynamically laying out Windows Forms is a huge pain. I don't have time to code this but the steps are:
Add FlowLayoutPanel to form as a container
Look through your Appointments and create label controls for each
Add the label controls to the panel's Controls collection
Assign an OnClick handler to each label control to toggle the color
Don't bother with databinding for this.
If you haven't changed the label's initial color from the default, this will toggle it:
private void label1_Click(object sender, EventArgs e)
{
var lbl = (Label)sender;
var toggle = lbl.ForeColor == SystemColors.ControlText;
lbl.ForeColor = toggle ? Color.Red : SystemColors.ControlText;
}
You could add each text field as a member of a Label or List view item. Then handle the "OnClick" or "SelectedIndexChanged" event. To create an an OnClick event handler double click on the control in the design view. Edit the handler like this:
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
listView1.SelectedItems[0].ForeColor = Color.Red;
}
If you are unsure about event handlers, don't be put off they are quite easy, just look them up here perhaps. If the list view is not what you are looking for, try the same approach on a different control.
I guess I can't comment on Jamie's answer, but raklos you can programmatically add the OnClick method by doing:
label.Click += new EventHandler(label_Click);
Visual Studio should auto-generate the stubs for you when you start typing that out.
Something like this could get you started:
private void label_Click(object sender, EventArgs e) { ToggleTextColor((Label)sender); }
private void ToggleTextColor(Control control)
{
var currentColor = control.ForeColor;
control.ForeColor = currentColor == Color.Red ? Color.Black : Color.Red;
}
You can cheat and make create it in a WebBrowserControl.
You will be in familiar ground.
Use ObjectforScripting for WeBbrowser <=> winforms communication.
http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.objectforscripting.aspx

how to dynamically add combobox in windows forms(C#) and bound it to a column of a table in sql database

My windows form has an ADD button which adds a combo box to the form after each click. The problem is, i am not able to bind it to a table column at run time. Using an existing databinding source selects the same value in all the combo boxes. I am coding in C#
here is the sample code :
ComboBox ocbNext = new ComboBox();
//HAVE set the rest of the properties right, the problem is with the databinding
ocbNext.DataSource = this.dummysubjectBindingSource;
ocbNext.DisplayMember = "sub_name";
ocbNext.ValueMember = "sub_name";
this.Controls.Add(ocbNext);
I added a DataSet to the solution and droped the Employees table (from Northwind) in the designer, which automatically created the employeesBindingSource. I dropped a combobox and a button on the Form and I set the DataSource and DataMember of the combo. Then I handled some events:
private void Form1_Load(object sender, EventArgs e)
{
this.employeesTableAdapter.Fill(this.dS.Employees);
}
private int _i = 0;
private void button1_Click(object sender, EventArgs e)
{
ComboBox combo = new ComboBox();
combo.DataSource = this.employeesBindingSource;
combo.DisplayMember = this.dS.Tables[0].Columns[++_i].ColumnName;
combo.Location = new Point(comboBox1.Location.X, comboBox1.Location.Y + comboBox1.Height * _i);
this.Controls.Add(combo);
}
So on each click, a new combo is added onto the form dynamically right under the previous combo. The combo is also bound to the next column in the Employees table (no boundary checks however).
As you can see, this is pretty easy stuff. Hope this helps.
Okay, so here is a variation of the code that could help you with that other question you asked in the comments of this answer.
It assumes you have a Form with a button and a DataSet with table Employees. On button click it creates a combo, and fills it with data (the Name column of Employees). Each time you add a combo, it gets its own copy of the data (this is important to be able to remove items from one combo at a time). Then, every time you select a value in the combo, the combo is disabled and the other combos don't have that selected value in their list.
private int _i = 0;
private void button1_Click(object sender, EventArgs e)
{
DataSet dataS = dS.Clone();
this.employeesTableAdapter.Fill((DS.EmployeesDataTable)dataS.Tables[0]);
BindingSource bindSource = new BindingSource(dataS, "Employees");
ComboBox combo = new ComboBox();
combo.Name = this.dS.Tables[0].Columns[0].ColumnName + (++_i).ToString();
combo.DataSource = bindSource;
combo.DisplayMember = this.dS.Tables[0].Columns[1].ColumnName; //This column is the Name of Employee
combo.Location = new Point(button1.Location.X, button1.Location.Y + combo.Height * _i);
combo.SelectedIndexChanged += new EventHandler(comboBox_SelectedIndexChanged);
this.Controls.Add(combo);
}
private void comboBox_SelectedIndexChanged(object sender, EventArgs e)
{
foreach (Control ctrl in this.Controls)
{
if (ctrl is ComboBox && ctrl != sender && ctrl.Enabled)
{
((BindingSource)((ComboBox)ctrl).DataSource).RemoveAt(((ComboBox)sender).SelectedIndex);
}
}
((ComboBox)sender).Enabled = false;
}
This is pretty close to what you require, or easily adaptable to meet your expectations. Enjoy and please select an answer as the accepted one. Thanks!
Option 1: Fill the combobox with strings:
this.comboBox1.Items.Add("Syed");
this.comboBox1.Items.Add("Baqar");
Option 2: Fill the combobox with an array of strings:
this.comboBox1.Items.AddRange(new object[] { "Syed", "Baqar" });
You need to add controls to the parent window first, and then set the data source.
ComboBox ocbNext = new ComboBox();
this.Controls.Add(ocbNext);
ocbNext.DisplayMember = "sub_name";
ocbNext.ValueMember = "sub_name";
ocbNext.DataSource = this.dummysubjectBindingSource;
Should be fine if you create a new local ComboBox variable in the clickevent. If you use a global variable for the ComboBox this might explain your problems. But without a sample how you're doing it's hard to see what's really happening, so think this is just a rough guess

How can I read a dynamically created textbox

I create some dynamic textbox's and a button in a placeholder and would like to save info in textbox's when button is clicked but not sure how to retrieve data from the textbox
LiteralControl spacediv3 = new LiteralControl("&nbsp&nbsp");
Label lblComText = new Label();
lblComTitle.Text = "Comment";
TextBox txtComment = new TextBox();
txtComment.Width = 200;
txtComment.TextMode = TextBoxMode.MultiLine;
phBlog.Controls.Add(lblComText);
phBlog.Controls.Add(spacediv3);
phBlog.Controls.Add(txtComment);
Button btnCommentSave = new Button();
btnCommentSave.ID = "mySavebtnComments" ;
btnCommentSave.Text = "Save ";
phBlog.Controls.Add(btnCommentSave);
btnCommentSave.CommandArgument = row["ID"].ToString();
btnCommentSave.Command += new CommandEventHandler(btnSave_Click);
protected void btnSave_Click(object sender, CommandEventArgs e)
{
firstelement.InnerText = txtComment.text // this gives error on txtComment.text
}
You need to get a reference to your control in btnSave_Click. Something like:
protected void btnSave_Click(object sender, CommandEventArgs e)
{
var btn = (Button)sender;
var container = btn.NamingContainer;
var txtBox = (TextBox)container.FindControl("txtComment");
firstelement.InnerText = txtBox.text // this gives error on txtComment.text
}
You also need to set the ID on txtComment and recreate any dynamically created controls at postback.
You will need some mechanism to create a relation between the Button and the TextBox obviously. In winforms this would be easy, where each control has a Tag property, which can contain a reference to pretty much anything. The web controls don't have such a property (that I know of), but it is still easy to maintain such relations. One approach would be to have Dictionary in the page storing button/textbox relations:
private Dictionary<Button, TextBox> _buttonTextBoxRelations = new Dictionary<Button, TextBox>();
When you create the button and textbox controls, you insert them in the dictionary:
TextBox txtComment = new TextBox();
// ...
Button btnCommentSave = new Button();
// ...
_buttonTextBoxRelations.Add(btnCommentSave, txtComment);
...and then you can look up the text box in the button's click event:
protected void btnSave_Click(object sender, CommandEventArgs e)
{
TextBox commentTextBox = _buttonTextBoxRelations[(Button)sender];
firstelement.InnerText = txtComment.text // this gives error on txtComment.text
}
Try during postback to load txtComment (with the same ID) in overridden LoadViewState method after calling base.LoadViewState. In this case you do load it before postback data are handled and txtComment control comes loaded.
Add an 'ID' to the textbox
txtComment.ID = "txtComment"
Request the information from the submitted form (provided you have a form on the page)
comment = Request.Form("txtComment")

Categories