Adding controls dynamically to an UpdatePanel in ASP.NET AJAX - asp.net

I have the following really simple code
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:PlaceHolder ID="PlaceHolder1" runat="server">
</asp:PlaceHolder>
<asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
</ContentTemplate>
</asp:UpdatePanel>
And the codebehind
protected void Button1_Click(object sender, EventArgs e)
{
Literal literal = new Literal();
literal.Text = DateTime.Now.ToString();
literal.ID = DateTime.Now.Ticks.ToString();
// These both work fine the first time the button is clicked
// but the second time nothing is added.
UpdatePanel1.ContentTemplateContainer.Controls.Add(literal);
PlaceHolder1.Controls.Add(literal);
}
My problem comes in that the Literal control is only ever added once. I've scoured google and blog sites (plus books) but without any luck. What am I missing?

In asp.net, the controls in the ASPX file are automatically generated on each postback. The controls you've created are not in the ASPX code so the framework does not create them for you. The first time you execute the Button1_Click method, you add one extra control to the page. The second time you execute the Button1_Click method, you're on another post back and that first extra button has been forgotten about. So the result of that postback is you get one extra button again.
This will create one extra control each time you click the button (although the timestamps will update each time you press the button because the controls are being re-created)
protected void Button1_Click(object sender, EventArgs e)
{
int count = 0;
if (ViewState["ButtonCount"] != null)
{
count = (int)ViewState["ButtonCount"];
}
count++;
ViewState["ButtonCount"] = count;
for (int i = 0; i < count; i++)
{
Literal literal = new Literal();
literal.Text = DateTime.Now.ToString();
literal.ID = DateTime.Now.Ticks.ToString();
UpdatePanel1.ContentTemplateContainer.Controls.Add(literal);
PlaceHolder1.Controls.Add(literal);
}
}

I agree to the answer above, However this approach will not save the state of the dynamic controls (or to be accurate, it will save the state but not load them back).
Load view state is called in Load event section of page life cycle,where it assigns back the control values saved in view state.
However if the controls are not created by this time, They can not be loaded with previous data so for the state to be maintained, the new controls must be recreated on or before load event.
protected void Page_Load(object sender, EventArgs e)
{
//PS: Below approach saves state as id is constant, it simply generates a new control with same id hence viewstate loads the value
if (IsPostBack)
{
int count = 0;
if (ViewState["ButtonCount"] != null)
{
count = (int)ViewState["ButtonCount"];
}
count++;
ViewState["ButtonCount"] = count;
for (int i = 0; i < count; i++)
{
TextBox literal = new TextBox();
//literal.Text = DateTime.Now.ToString();
literal.ID = "Textbox" + i.ToString();
//UpdatePanel1.ContentTemplateContainer.Controls.Add(literal);
PlaceHolder1.Controls.Add(literal);
}
}
}
Dynamically adding controls
View State and postback

Related

how to store a label control text into a textbox control value

i am trying to set the value of a textbox control in my aspx page as the value of a label text. I am using the following code but nothing happens. I have tried from the code behind file using c# and then I want to assign the textbox value to a session variable. If I just assign a string value like "Hello"it works, but otherwise nothing works.
protected void btnBook_Click(object sender, EventArgs e)
{
txtmtcid.Text = blbtest.Text;
Session["mtcid"] = txtmtcid.Text;
//Response.Redirect("booknow.aspx");
}
}
I also tried with Javascript, but no use:
var mtcid = parsedData.employeeCode;
document.getElementById('txtmtcid').value = mtcid;
The above js code works fine if I am assigning the value of mtcid to a label text, but not for the text box. please help.
You don't show things that could be messing this up.
and we can't see your markup used.
What does your page load event look like. Keep in mind that EVERY button click, post-back or ANY control on the page with a event code stub WILL RUN the page load event EVERY time. the page load event runs every time, and BEFORE your button click code runs.
So, if I have this markup:
<asp:Label ID="blbtest" runat="server" Text="zoo"></asp:Label>
<br />
<asp:TextBox ID="txtmtcid" runat="server"></asp:TextBox>
<br />
<br />
<asp:Button ID="Button1" runat="server" Text="Button"
onclick="Button1_Click" />
<br />
And then code behind of this:
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
txtmtcid.Text = blbtest.Text;
}
I then get this when I click on the button
So, we can see how the lable text is now copy to the text box.
You have to post more markup, and give futher detilas (such as some grid view, repeater or any other boatload of features that well explain your issue).
Note that you can double click on the button in the web forms designer to create a event click for the button. Its possible that no event code for the button exists, and your button click code and code behind never runs.
So this is the markup:
<asp:Label ID="blbtest" runat="server" ClientIDMode="Static">
</asp:Label>
<asp:Button ID="btnBook" runat="server" Text="Book Now"
CssClass="spaces-info__button" OnClick="btnBook_Click"/>
<asp:TextBox ID="txtmtcid" runat="server">
</asp:TextBox>
Code behind:
protected void Page_Load(object sender, EventArgs e)
{
if (!(Session["username"] == null))
{
string usn = Session["username"].ToString();
lblusn.Text = usn;
}
}
protected void btnBook_Click(object sender, EventArgs e)
{
txtmtcid.Text = blbtest.Text;
Session["mtcid"] = txtmtcid.Text;
Response.Redirect("booknow.aspx");
}
updated js:
$(function () {
//dom is ready
var request = new XMLHttpRequest;
var usn = document.getElementById('lblusn').innerHTML;
//var usn = "juhaina.ahmed";
console.log(usn);
request.open('GET', "URL" + usn + ""); //of course I have replaced
the URL here
request.onload = function () {
var response = request.response;
var parsedData = JSON.parse(response);
console.log(parsedData);
var nm = parsedData.fullName;
document.getElementById('lblfullnm').innerHTML = nm;
var mtcid = parsedData.employeeCode;
document.getElementById('blbtest').innerHTML = mtcid;
document.getElementById('txtmtcid').value =
document.getElementById('blbtest').innerHTML
};
request.send();
});
I am new to js, and asp.net, so trying to browse whatever possible and work things out here. The session variable value is just not getting passed to next page. Honestly, i dont need the textbox, I dont know if label text can be stored in session variables. If thats possible, then all I want to do is assign the blbtest label text to the session variable, but that also didnt work,but if I am hard coding it like:
Session["mtcid"]="D-11234"
this works and the value of session variable is passed.
hence I am trying now with textbox. Please let me know if theres a better approach to this.
If there is a way to avoid the use of the label and textbox and simply pass the session variable, Session["username"] from the code behind to the javascript, that would be great. how can I do it?

why the form posted values are not those submitted by users?

I use Asp.net web forms. I have a form with a table and a combo box. The table changes as the selected item of the combo box changes. The combo box is an asp.net control and I set autopostback = true. The table is also an asp.net control, and all table cells are created/rendered in the server side.
Users will input values in the table and submit it to the server.
The problem I find is that when a user changes the selected item of the combo box, the table changes and the web page rendered correctly. Then the user inputs some values and clicks submit. From the server side, the value I get is the default values of the table, not the user inputs. If the user submits again, the server side can get the user inputs.
Here is the code I write to reproduce this issue. I create a default web form project, add a new web from which inherits the site master. To reproduce, take following steps: 1. select one radio button 2. submit and you will see a text about your selection at the top of the page. 3. change the combo box selection 4. select another radio button 5. submit and you will find the bug. 6. redo 4 and 5, you will find the text correct.
<%# Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="PostBackUsingMasterPage.aspx.cs" Inherits="WebFormBug.PostBackUsingMasterPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="FeaturedContent" runat="server">
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="MainContent" runat="server">
<asp:DropDownList ID="comboBox" runat="server" AutoPostBack="true" OnSelectedIndexChanged="UpdateTable">
<asp:ListItem>Apple</asp:ListItem>
<asp:ListItem>Beet</asp:ListItem>
<asp:ListItem>Citron</asp:ListItem>
</asp:DropDownList>
<asp:Label ID="userInput" runat="server"></asp:Label>
<asp:Table runat="server" ID="testTable"> </asp:table>
<asp:Button ID="submit" runat="server" Text="Submit for validation" OnClick="SubmitButton_Click" />
</asp:Content>
The aspx.cs is like this
using System;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
namespace WebFormBug
{
public partial class PostBackUsingMasterPage : Page
{
private string _scope;
protected void Page_Load(object sender, EventArgs e)
{
_scope = comboBox.SelectedValue ?? "Apple";
PopUpTable(_scope);
}
private void PopUpTable(string item)
{
testTable.Rows.Clear();
var row = new TableRow();
row.Cells.Add(new TableCell {Text = item});
row.Cells.Add(AddRadioButtons(item));
testTable.Rows.Add(row);
}
private TableCell AddRadioButtons(string name)
{
var cell = new TableCell();
var radioButtons = new HtmlInputRadioButton[5];
for (var i = 0; i < 3; i++)
{
radioButtons[i] = new HtmlInputRadioButton { Name = name, Value = name + " " + i };
cell.Controls.Add(radioButtons[i]);
var label = new Label { Text = name + " " + i };
cell.Controls.Add(label);
}
return cell;
}
protected void UpdateTable(object sender, EventArgs e)
{
PopUpTable(comboBox.SelectedValue);
}
protected void SubmitButton_Click(object sender, EventArgs e)
{
int valueIndex = 1;
for (int i = 0; i < testTable.Rows.Count; i++)
{
var row = testTable.Rows[i];
string inputValue = null, inputName = null;
foreach (var ctrl in row.Cells[valueIndex].Controls)
{
if (ctrl is HtmlInputRadioButton)
{
var radioInput = (HtmlInputRadioButton) ctrl;
if (!radioInput.Checked) continue;
inputValue = radioInput.Value;
inputName = radioInput.Name;
break;
}
}
if (inputName != null && inputValue != null)
{
userInput.Text = inputName + " " + inputValue;
}
}
}
}
}
Preparation knowledge of ASP.NET WebForm: dynamically added table data is missing from form post asp.net table adding rows dynamically don't remain after postback. Your sample is the case - you are composing table data dynamically.
Solution for posting back dynamic table data is to re-create the form data in each post back in (and should ONLY in) page Load method. and your sample is doing this (the PopUpTable method is always called in Page_Load).
However, in your code Page_Load is not the only place doing table re-creation, but also in OnSelectedIndexChanged which results in cleaning your table data. Actually, you don't need register this event.
So, solution (sorry for attaching the code as image, but I found attaching large segment of code is very hard to format):
Remove OnSelectedIndexChanged
Change code behind as below:
Try this:
in page load:
if(!IsPostBack)
{
// set data to table
}
I'm assuming you have updatepanel with which the change of the selected index on the dropdown updates the radiobuttons. You could try changing the eventhandler for the dropdown to
protected void UpdateTable(object sender, EventArgs e)
{
if (!IsPostBack)
{
PopUpTable(comboBox.SelectedValue);
}
}

How to add persistent dynamic controls based on user input (not on initial page load)

I am familiar with creating and persisting dynamic controls on the first load of a page and on subsequent postbacks but I am having trouble with the following user initiated scenario...
In my demo I have a placeholder, two buttons and a literal
<div>
<asp:PlaceHolder ID="phResponses" runat="server" />
</div>
<div>
<asp:Button ID="btnAdd" Text="Add" runat="server" OnClick="Add"/>
<asp:Button ID="btnInspect" Text="Inspect" runat="server" OnClick="Inspect"/>
</div>
<div>
<asp:Literal ID="litResult" runat="server"/>
</div>
I want the user to be able to click the add button to provide a response so I have...
protected void Page_Init(object sender, EventArgs e)
{
BuildControls();
}
protected void Add(object sender, EventArgs e)
{
BuildControls();
}
protected void BuildControls()
{
phResponses.Controls.Add(new LiteralControl { ID = "response_" + _Count.ToString() });
_Count++;
}
_Count is a static member variable to enable me to have unique ids for the new controls. I realise I need to rebuild the dynamic controls on Page_Init but the problem is that I end up with 2 new Literal controls on every postback. Also if any Text property is put into the new controls it is lost when the controls are rebuilt.
So how do I avoid adding multiple controls and how do I persist newly added properties when rebuilding these controls?
I use the following to inspect the responses
protected void Inspect(object sender, EventArgs e)
{
foreach (var control in phResponses.Controls)
{
if (control is LiteralControl)
{
litResults.Text += "<p>" + control.Text + " : " + control.ID + "</p>";
}
}
}
Which itself adds another unwanted control because of the rebuilding on Page_Init
I'd not sure that I quite understand what you're asking, but it looks like you just want to ensure that BuildControls is only called once per lifecycle. You could do that by making the following changes:
Add a new private bool _isControlsBuilt = false;.
Change Page_Init to check _isControlsBuilt before calling BuildControls.
Set _isControlsBuilt to true within BuildControls.
Make sure that BuildControls occurs earlier in the page lifecycle than Page_Init.
As for losing the values of controls on postback, it'll be that they're never hitting the viewstate. I'm not sure if it'd work, but my first guess would be to add a line to the end of BuildControls to call Page.RegisterRequiresControlState:
protected void BuildControls()
{
LiteralControl newLiteral = new LiteralControl { ID = "response_" + _Count };
this.RegisterRequiresControlState(newLiteral);
phResponses.Controls.Add(newLiteral);
_Count++;
_isControlsBuilt = true;
}
If that doesn't work (which might imply that it's the _view_state, not the _control_state that matters to you here), you may need to look at rolling your own viewstate. I wrote about how to do that in my answer to #3854193, which you might find useful.

CheckedChanged EventHandler of dynamically added Checkboxes not firing inside UpdatePanel of a Repeater

I´ve read most posts here but i can´t figure out why the "CheckedChanged" Event is not firing. Here is my situation.
I´m using a Repeater to generate Items out of a Database. Each ReapeaterItem should include an UpdatePanel, because i have to Update the Controls inside the UpdatePanel and do not want to reload the complete page. Inside these dynamically generated UpdatePanels (each RepeaterItem has one) i´m adding up to three Checkboxes dynamically (based on the Database). These Checkboxes need to fire the "CheckedChanged" event, because on some conditions i want to enable/disable/check/uncheck Checkbox1, 2 or 3 based on business logic. ... Hope you got this so far. I´m adding all Controls and have the EventHandler Added. But the generated Code does not reflect the Event Handler. I tried OnItemDataBound, OnItemCreated, PreRender, ... Events to add the Eventhandler too, but i was not able to find the CheckBox-Control with the ID.
I´m totally lost with this and on the way to use Buttons instead of Checkboxes. From what i read so far is that with Buttons i can use the CommandName from the Button and the ItemCommand-Event from the Repeater to get a workaround, but then i need to reflect the "Check" on the Page in some way.
btw, every Repeater (8) sits inside an ajaxtoolkit-accordion control.
Here i give you some Code:
aspx-Page
<asp:Repeater ID="RepeaterAccordionPane2" runat="server">
<ItemTemplate>
HTML Stuff<%# DataBinder.Eval(Container.DataItem, "Header")%>HTML Stuff<%# DataBinder.Eval(Container.DataItem, "Beschreibung")%></td>
<asp:UpdatePanel ID="UpdatePanel2" runat="server" UpdateMode=Conditional>
<ContentTemplate>
</ContentTemplate>
</asp:UpdatePanel>
HTML Stuff
</ItemTemplate>
</asp:Repeater>
Here is the Page_Load Part
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
dvAlleArtikel = new System.Data.DataView(...Database...);
[... some other code here ...]
RepeaterAccordionPane2.DataSource = dvAlleArtikel;
//RepeaterAccordionPane2.ItemCreated +=new RepeaterItemEventHandler(RepeaterAccordionPane2_ItemCreated);
//RepeaterAccordionPane2.PreRender +=new EventHandler(RepeaterAccordionPane2_PreRender);
RepeaterAccordionPane2.DataBind();
int nUpdatePanelIndex = 0;
foreach (Control crInRepeater in RepeaterAccordionPane2.Controls)
{
if (crInRepeater.GetType() == typeof(RepeaterItem))
{
foreach (Control crInRepeaterItem in crInRepeater.Controls)
{
if (crInRepeaterItem.GetType() == typeof(UpdatePanel))
{
LiteralControl litTabelleBeginn = new LiteralControl("<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"2\">");
((UpdatePanel)crInRepeaterItem).ContentTemplateContainer.Controls.Add(litTabelleBeginn);
if (dvAlleArtikel[nUpdatePanelIndex]["ArtNr1"].ToString() != "0")
{
CheckBox CheckBox1 = new CheckBox();
CheckBox1.ID = dvAlleArtikel[nUpdatePanelIndex]["ArtNr1"].ToString();
CheckBox1.Text = (dvAlleArtikel[nUpdatePanelIndex]["CheckBoxLbl1"].ToString() == "" ? "leer" : dvAlleArtikel[nUpdatePanelIndex]["CheckBoxLbl1"].ToString());
CheckBox1.AutoPostBack = true;
CheckBox1.CheckedChanged +=new EventHandler(CheckBox1_CheckedChanged);
LiteralControl litNeueTabellenZeileBeginn = new LiteralControl("<tr><td width=10><img src=\"images/helper/spacer.gif\" width=\"10\"></td><td height=\"20\">");
LiteralControl litNeueTabellenZeileEnde = new LiteralControl("</td><td width=\"100\" height=\"20\">" + dvAlleArtikel[nUpdatePanelIndex]["ArtPrice1"].ToString() + " € </td></tr>");
((UpdatePanel)crInRepeaterItem).ContentTemplateContainer.Controls.Add(litNeueTabellenZeileBeginn);
((UpdatePanel)crInRepeaterItem).ContentTemplateContainer.Controls.Add(CheckBox1);
((UpdatePanel)crInRepeaterItem).ContentTemplateContainer.Controls.Add(litNeueTabellenZeileEnde);
}
[... some other code here...]
LiteralControl litTabelleEnde = new LiteralControl("</table>");
((UpdatePanel)crInRepeaterItem).ContentTemplateContainer.Controls.Add(litTabelleEnde);
nUpdatePanelIndex++;
}
}
}
}
This code is never reached:
protected void CheckBox1_CheckedChanged(object sender, EventArgs e)
{
int foo = 0;
}
This is the CheckBox-Code generated:
<input id="AccordionPane2_content_RepeaterAccordionPane2_ctl00_6200" type="checkbox" name="AccordionPane2_content$RepeaterAccordionPane2$ctl00$6200" onclick="javascript:setTimeout('__doPostBack(\'AccordionPane2_content$RepeaterAccordionPane2$ctl00$6200\',\'\')', 0)" />
The Event is generated, but when i click the Checkbox all Content in the UpdatePanel is gone and the CheckedChanged-EventHandler is not fired.
What am i doing wrong?
Thanks to all advice, i´m really stuck.
mk
The first time the page loads you are adding all the checkboxes to the Controls collection, and they get rendered. When you do a postback (through the CheckBox's AutoPostBack) you have a check if(!IsPostBack) that doesn't allow the checkboxes to be added to the Controls collection on the postback. Because of that, you won't see the controls and the page, and when the page lifecycle tries to call the events (which occurs AFTER Page_Load), the controls that created the events are no longer there.
You will need to refactor your Page_Load method so it does two things - 1, regardless of the value of IsPostBack bind the repeaters and create the dynamic controls. 2, if IsPostBack==false, i.e., an initial load, then set the values of the dynamic controls. you don't want to set the values of the dynamic controls when IsPostBack==true because then you will lose the values the user entered.
also, just a note:
if (crInRepeater.GetType() == typeof(RepeaterItem))
can be rewritten as:
if (crInRepeater is RepeaterItem)

How to programmatically create and use a list of checkboxes from ASP.NET?

I have a page with a table of stuff and I need to allow the user to select rows to process. I've figured out how to add a column of check boxes to the table but I can't seem to figure out how to test if they are checked when the form is submitted. If they were static elements, I'd be able to just check do this.theCheckBox but they are programaticly generated.
Also I'm not very happy with how I'm attaching my data to them (by stuffing it in there ID property).
I'm not sure if it's relevant but I'm looking at a bit of a catch-22 as I need to known which of the checkboxes that were created last time around were checked before I can re-run the code that created them.
Edit:
I've found an almost solution. By setting the AutoPostBack property and the CheckedChanged event:
checkbox.AutoPostBack = false;
checkbox.CheckedChanged += new EventHandler(checkbox_CheckedChanged);
I can get code to be called on a post back for any check box that has changed. However this has two problems:
The call back is processed after (or during, I'm not sure) Page_Load where I need to use this information
The call back is not called for check boxes that were checked when the page loaded and still are.
Edit 2:
What I ended up doing was tagging all my ID's with a know prefix and stuffing this at the top of Form_Load:
foreach (string v in this.Request.Form.AllKeys)
{
if (v.StartsWith(Prefix))
{
var data = v.Substring(Prefix.Length);
}
}
everything else seems to run to late.
I'm going to assume you're using a DataList but this should work with and Control that can be templated. I'm also going to assume you're using DataBinding.
Code Front:
<asp:DataList ID="List" OnItemDataBound="List_ItemDataBound" runat="server">
<ItemTemplate>
<asp:CheckBox ID="DeleteMe" runat="server"/>
<a href="<%# DataBinder.Eval(Container, "DataItem.Url")%>" target="_blank">
<%# DataBinder.Eval(Container, "DataItem.Title")%></a>
</ItemTemplate>
</asp:DataList>
<asp:Button ID="DeleteListItem" runat="server" OnClick="DeleteListItem_Click" ></asp:Button>
Code Behind:
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadList();
}
protected void DeleteListItem_Click(object sender, EventArgs e)
{
foreach (DataListItem li in List.Items)
{
CheckBox delMe = (CheckBox)li.FindControl("DeleteMe");
if (delMe != null && delMe.Checked)
//Do Something
}
}
LoadList();
}
protected void LoadList()
{
DataTable dt = //Something...
List.DataSource = dt;
List.DataBind();
}
protected void List_ItemDataBound(object sender, DataListItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
{
string id = DataBinder.Eval(e.Item.DataItem, "ID").ToString();
CheckBox delMe = (CheckBox)e.Item.FindControl("DeleteMe");
if (delMe != null)
delMe.Attributes.Add("value", id);
}
}
}
First, make sure that each Checkbox has an ID and that it's got the 'runat="server"' in the tag.
then use the FindControl() function to find it.
For example, if you're looping through all rows in a GridView..
foreach(GridViewRow r in Gridview1.Rows)
{
object cb = r.FindControl("MyCheckBoxId");
if(r != null)
{
CheckBox chk = (CheckBox)cb;
bool IsChecked = chk.Checked;
}
}
Postback data is restored between the InitComplete event and the PreLoad event. If your checkboxes are not created until later then the checkboxes will play "catch up" with their events and the data will be loaded into the control shortly after it is created.
If this is to late for you then you will have to do something like what you are already doing. That is you will have to access the post data before it is given to the control.
If you can save the UniqueId of each CheckBox that you create then can directly access the post data without having to given them a special prefix. You could do this by creating a list of strings which you save the ids in as you generate them and then saving them in the view state. Of course that requires the view state to be enabled and takes up more space in the viewstate.
foreach (string uniqueId in UniqueIds)
{
bool data = Convert.ToBoolean(Request.Form[uniqueId]);
//...
}
Your post is a little vague. It would help to see how you're adding controls to the table. Is it an ASP:Table or a regular HTML table (presumably with a runat="server" attribute since you've successfully added items to it)?
If you intend to let the user make a bunch of selections, then hit a "Submit" button, whereupon you'll process each row based on which row is checked, then you should not be handling the CheckChanged event. Otherwise, as you've noticed, you'll be causing a postback each time and it won't process any of the other checkboxes. So when you create the CheckBox do not set the eventhandler so it doesn't cause a postback.
In your submit button's eventhandler you would loop through each table row, cell, then determine whether the cell's children control contained a checkbox.
I would suggest not using a table. From what you're describing perhaps a GridView or DataList is a better option.
EDIT: here's a simple example to demonstrate. You should be able to get this working in a new project to test out.
Markup
<form id="form1" runat="server">
<div>
<table id="tbl" runat="server"></table>
<asp:Button ID="btnSubmit" runat="server" Text="Submit"
onclick="btnSubmit_Click" />
</div>
</form>
Code-behind
protected void Page_Load(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
var row = new HtmlTableRow();
var cell = new HtmlTableCell();
cell.InnerText = "Row: " + i.ToString();
row.Cells.Add(cell);
cell = new HtmlTableCell();
CheckBox chk = new CheckBox() { ID = "chk" + i.ToString() };
cell.Controls.Add(chk);
row.Cells.Add(cell);
tbl.Rows.Add(row);
}
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
foreach (HtmlTableRow row in tbl.Rows)
{
foreach (HtmlTableCell cell in row.Cells)
{
foreach (Control c in cell.Controls)
{
if (c is CheckBox)
{
// do your processing here
CheckBox chk = c as CheckBox;
if (chk.Checked)
{
Response.Write(chk.ID + " was checked <br />");
}
}
}
}
}
}
What about using the CheckBoxList control? I have no Visual Studio open now, but as far as I remember it is a DataBound control, providing DataSource and DataBind() where you can provide a list at runtime. When the page does a postback you can traverse the list by calling something like myCheckBoxList.Items and check whether the current item is selected by calling ListItem.Selected method. This should work.
Add them in an override of the CreateChildControls method of the Page. Be sure to give them an ID! This way they get added to the control tree at the correct time.
IMHO The best way would be to use DataBound Templated Control though, i.e. something like a ListView (in .NET 3.5). then in pageload after postback traverse all items in the databound control and use item.FindControl to get at the actual checkbox.
What I ended up doing was tagging all my ID's with a know prefix and stuffing this at the top of Form_Load:
foreach (string v in this.Request.Form.AllKeys)
{
if (v.StartsWith(Prefix))
{
var data = v.Substring(Prefix.Length);
}
}
everything else seems to run to late.

Resources