Retrieve data from dynamically created controls - c#

I am dynamically creating several dropdown list on the selection changed event of a main (static) dropdown list. These are created in The TableCell of default Table. When submit button is clicked I need to load a new page with selected values of dropdown as parameters. Basically I need to get the dropdown results in the second page.
This is how dropboxes are created:
while (reader.Read())
{
pcID = int.Parse(reader["fk_pcID"].ToString());
pcDesc = GetpcDescription(pcID);
List<Product> prodList = GetProductsBypcID(pcID);
DropDownList ddList = new DropDownList();
ddList.ID = "ddlPC" + pcID;
foreach(Product prod in prodList)
{
ddList.Items.Add(new ListItem(prod.ProductName, prod.ProductID.ToString()));
}
TableCell cell1 = new TableCell();
cell1.Text = pcDesc;
TableCell cell2 = new TableCell();
cell2.Controls.Add(ddList);
TableRow row = new TableRow();
row.Cells.Add(cell1);
row.Cells.Add(cell2);
table.Rows.Add(row);
}
EDIT: The above code runs at the selection changed event of a dropdown which is set to runat server. But dynamically created dropdowns are not set to run at server

Are these drop-down boxes runat="server"? Meaning: did you created them programmaticly via a .net post-back event through the code behind? If so, just get the selected value the same as you would with any other control, and then pass it through a query string or a cookie.
Are these standard html drop-down lists? Good luck reading them from a code-behind. That gets you all tangled up in the viewstate, and while technically possible, is realistically not feasible.
If the second option is the case, it might be a much better option to have your button target a JavaScript function that gets the selected values and then passes them via querystring. Then on the other page you can read the querystrings from the code-behind, or on the client-side.

This sounds like a good candidate for the DynamicControlsPlaceholder. It will preserve your dynamic controls automatically, without requiring any additional code on the page. If you need to create the controls OnSelectedIndexChanged, I think this might be the simplest solution.
It's a free component, and you can download it here.
http://www.denisbauer.com/ASPNETControls/DynamicControlsPlaceholder.aspx

Related

ASP.NET GridView - dynamic columns blank on postback, how to identify them for removal?

I've a GridView with a set of fixed (written into the ASPX markup) columns. Onto the end of this column collection, during the page load, I add another few columns (the number of columns varies according to how many key-value pairs I have stored in relation to the grid entities) and I set the IDs of the controls I dynamically add, to relate to the key:
//Dictionary<string, string> myDictionary ...
foreach (string in myDictionary.Keys)
{
var tf = new TemplateField();
tf.HeaderText = k;
tf.ItemTemplate = new Label("key_" + k);
gridview.Columns.Add(tf);
}
During the RowDataBound event I look through the key value pairs, call a e.Row.FindControl to find the label that should have this value, and populate the value:
foreach (var k in myDictionary.Keys)
{
Label lb = (Label)e.Row.FindControl("key_" + k);
lb.Text = myDictionary[k];
}
This works fine for the initial display, but on postback the page load code runs again. At this time, the gridview seems to have re-instated all the dynamic columns I made, but it hasn't put any data into them. If I wrap my column adding code in an if(!IsPostback) to prevent them being added again on postback.. then I'll see the columns I originally added, but they're blank. If I don't use an IsPostback check, then I'll see a duplicate set of columns in the rendered page: one blank, the other containing values. The controls within the blank columns don't seem to have the same IDs any more, so when my RowDataBound fires, e.Row.FindControl("key_" + k) returns null. Of course, if I don't check for postback, and just add the columns again, the newly added set of columns will have controls with correctly named IDs and they'll get populated..
To counter the ever growing set of blank columns, I plan to remove (in page load) any columns I dynamically added, that have been re-instated with the wrong cell-control IDs, and add them again. I can do this by looping backwards through the column collection until I hit a column that is certain to be the last column that is present in the ASPX markup, but the only thing I can see to identify that column by is the header text assigned in the markup (as it doesn't have an ID of its own). Here's the markup, for example:
This feels like an awful way to do things:
for(int i = gv.Columns.Count-1; gv.Columns[i].HeaderText != "Edit Profile"; i--)
gv.Columns.RemoveAt(i); //remove all columns after the 'Edit Profile' one
..not least because there's a bug waiting to happen if the header text changes, or if the key value pairs list ever contains "Edit Profile" as a key..
But how can I better determine which column in a gridview is there because it was added in the markup, versus one that was added dynamically?
Alternatively, is there a better way to re-use the dynamically added columns without deleting them and re-adding them (with corrected IDs)? As noted they're there, but the cells have no data and the Label IDs within the cells are all changed when I get the grid back during a postback, so I can't find them to restore their values..
You can try to use a datatable instead of adding columns in gridview, it used to work very well with me you just need to initialise the datatable and add as much columns and rows as you want, and at the end of the if(!IsPostback) on pageload bind the gridview to the datatable without the need to define the gridview_rowdatabound.
For example:
if (!Page.IsPostBack) {
foreach (string s in mydictionary.Keys) {
dt1.Columns.Add(s);
}
DataRow dr = dt.NewRow();
foreach (column col in dt1.Columns) {
dr[i].value = mydictionary(col.columnname);
i = i + 1;
}
dt1.Rows.Add(dr);
gridview1.datasource = dt1;
gridview1.databind();
}
Note:
I converted from vb.net to C# please notice me in case of error.
Let Autogenerate columns in gridview=true

Event Handler is not getting called for dynamically created checkboxes

I am kind of new to C# and Asp.Net, so this question might sound repetitive but I am not able to find a solution for this particular problem.
I have two buttons on my HTML page and a single class in .cs file. On one of the button clicks, I create a table programmatically (dynamically).
The table contains some checkboxes which are also created dynamically.
Table creation is one of the last tasks that I perform. Before that, I read several files and extract data from them to create the table. After the table is drawn, the user can select one or more checkboxes.
Now, how on second button click, can I know that which of the checkboxes were checked before the page reload? Currently I have made all these checkboxes member variables of the the only class that I have in the .cs file.
I tried adding checkbox event handler through C# code. But the handler is not getting called when the checkbox is checked. I don't want to set the 'autopostback' property of the checkbox to true since if thats set true, the page reloads after checking one of the checkboxes. User should be able to select multiple checkboxes.
Add your checkboxes dynamically and set a unique name for each checkbox. Checkboxes are only posted back to the server if the checkbox is checked, so you can test to see if it is checked by checking Request.Form to see if the name exists. For example, lets say you named your check boxes chk_[0-9] (i.e. chk_0, chk_1 etc till 9), you could check if they ticked by doing:
for(int i=0; i < 10; i++)
{
string chk_name = "chk_" + i.ToString();
if (Request.Form[chk_name] != null)
{
//checkbox is checked
}
else
{
//checkbox is not checked
}
}

ASP:Table adding rows programmatically

I am trying to add rows programmatically to a server side table in asp.net. I have a button, and within the click event handler I have:
TableRow row = new TableRow();
TableCell cell = new TableCell();
cell.Controls.Add(new TextBox());
row.Cells.Add(cell);
myServersideTable.Rows.AddAt(myServersideTable.Rows.Count - 1, row);
All good, the code works the first time the button is clicked and a new row is added.
However, all subsequent button clicks don't add a new row. No error is thrown.
Why this might be happening?
You are adding a row dynamically, so when you postback you will have to again recreate the controls.
In this case you are using a Table and the row is added on first button click, so when you click again you will have to recreate the previous row again and one more for the current click
You can't do this because of the stateless nature of Http protocol. For more information please read ASP.NET page life cycle from the MSDN.

Read a dynamically created textbox in a Gridview

I am dynamically adding a textbox to certain rows (one column only) of a gridview. I add the controls with this insdie of a test condition (works fine):
TextBox txtASIN = new TextBox();
txtASIN.ID = "TxtASIN" + e.Row.RowIndex;
e.Row.Cells[4].Controls.Add(txtASIN);
int i = e.Row.Cells[4].Controls.Count; //TEST: This returns 1 correctly
I want the user to be able to enter values into one or more of these textboxes and then update the database with a single button click (not one click for each row). The problem I'm having is how to access those values on a button click event. I did a simple test this way to try to see the value in the second row but get null in temp1 (I am certain there is a value entered in that textbox):
protected void btnUpdate1_Click(object sender, EventArgs e)
{
TextBox temp = (TextBox)GridView2.Rows[1].FindControl("txt1");
string temp1 = temp.Text;
int i = GridView2.Row.Cells[4].Controls.Count; //TEST: This returns 0 incorrectly }
Once I can make this work, I can iterate through the rows and do what I need to do with the values. I don't know if the text entered in the textbox is actually readable without a postback but I'm otherwise stumped. Open to better suggestions on how to do this.
Thanks.
EDIT: Here is where I am now. I can see the textboxes in my column fine. I put a break in on a button that attempts to read them and this is what I'm seeing. If I check GridView2.Rows[0].Controls.Count, I get 8, which is the correect number of columns. If I check GridVeiw2.Rows[0].Cells[4].Controls.Count, I get 0, which is wrong because the textbox is there. I can get a Count of 1 right after I dynamically create it but not when I perform a subsequent button click.
Can anyone explain this? I feel if I can get past this holdup, I can get the rest done.
Thanks again.
You need to assign an ID to the TextBox controls and then access them by that ID in FindControl(). Also, make sure you're adding the controls in the Page's Init() method of the life-cycle. That way it gets added to ViewState.
TextBox txt1 = new TextBox();
txt1.ID = "txt1";
e.Row.Cells[4].Controls.Add(txt1);
EDIT: I just remembered another possible solution. Instead of programatically creating the TextBox controls in the code-behind just create a TemplateField in the GridView.
Add Textbox TemplateField Column To GridView Programmatically
I would try a different approach, putting the text box in the html markup of the page and then control the visible or readonly property of it on the ItemDataBound event. That way, the control will always be there and you don't have to worry about the lifecycle stuff.

PostbackUrl of dynamic GridViews not what I think they should be

I have a couple GridViews that are dynamically created and placed into a PlaceHolder. When I mouse over the Select button, it shows __doPostBack('ctl00$bodyPlaceHolder$ctl0X','Select$Y'), where X = what I think is the GridView/Control index for the page and Y = row number of that GridView.
Since it is dynamically creating the GridViews, it makes sense that names them ctl0X, but on the PostBack how do I use this information?
I wouldn't even have this problem if adding the SelectedIndexChanged EventHandler worked, but it never gets called.
I found one other question like this, but the answer involved adding a GridView within my GridViews, which would also have to be dynamic, which brings me back to the original problem.
Edit
Okay, so I set gridViewDynamic.ID = "blahblah" + r.LastName, thus giving each GridView a unique name, so on mouseover in the page I get __doPostBack('ctl00$bodyPlaceHolder$blahblahSmith',Select$Y, I still can't access the items on PostBack because they no longer exist. So, I added the same GridView creation code to an if(IsPostBack), then called GridView gView = (GridView)this.Page.FindControl(blahblahSmith). Great, gView isn't null. But all the data in the rows are. Calling gView.Rows[0] returns null.
Use Page.FindControl("TheNameYouGaveTheDynamicGridView")
GridView grid = Page.FindControl("TheNameYouGaveTheDynamicGridView") as GridView;
If you are using MasterPages, you need to take a different approach to find the control on the page, but it is the same premise.

Categories