As Pranay explained, it's because you are adding controls dynamically. You need to rebuild the page as it was before the postback. Furthermore, the Table control is not a good webcontrol when it comes to remembering what information was displayed earlier. You might have better luck with a Repeater, a DataList, or a DataGrid. A comparison is available in Deciding When to Use the DataGrid, DataList or Repeater (MSDN).
To demonstrate, I can show a short example of how you could go about implementing the Repeater, as that is the simple one of the controls IMO. So, instead of adding a table in a postback (such as a button click) just add the repeater in the markup, and set it to visible when you want to display the data. This way, you don't even have to bother about dynamic controls, it's there when you need it.
So, a basic markup for a repeater with a checkbox is as follows.
<asp:Repeater ID="myTable" runat="server">
<HeaderTemplate>
<table cellpadding="4" cellspacing="0">
<thead>
<tr>
<th></th>
<th>Name</th>
<th>Company</th>
</tr>
</thead>
<tbody>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<asp:HiddenField ID="uidfield" Value='<%# Eval("Uid") %>' runat="server" />
<asp:CheckBox ID="valuefield" Checked='<%# Eval("IsChecked") %>' runat="server" />
</td>
<td>
<asp:Label Text='<%# Eval("Name") %>' runat="server" />
</td>
<td>
<asp:Label Text='<%# Eval("Company") %>' runat="server" />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</tbody> </table>
</FooterTemplate>
</asp:Repeater>
As you can see, the table is built manually (you can use DataGrid instead if you don't want to do that). Now you can have a class which is your model, something like:
public class Person {
public Person() { }
public Person(Guid id, string name, string company) {
this.Uid = id;
this.Name = name;
this.Company = company;
}
public Guid Uid { get; set; }
public string Name { get; set; }
public string Company { get; set; }
}
And a viewmodel class that "accommodates the needs" of the view (as in your web page control). Note the extra property IsChecked, it shouldn't be a part of the model (how is a person checked?), but it fits well in the viewmodel class.
public class PersonViewModel {
private Person model;
public PersonViewModel(Person model) {
this.model = model;
}
public Guid Uid { get { return model.Uid; } }
public string Name { get { return model.Name; } }
public string Company { get { return model.Company; } }
public bool IsChecked { get; set; }
}
Okay, so on to the code behind. When using the repeater control you need to bind it to a list. An instance of something that inherits from IEnumerable will be just fine, so you need to hook it up.
In your code behind for your page, add these methods.
protected override void OnInit(EventArgs e) {
base.OnInit(e);
mailinglists.DataBinding += bindMyTable;
}
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
if (!Page.IsPostBack) {
DataBind();
}
}
private void bindMyTable(object sender, EventArgs e) {
// Are the conditions set for adding data to the table?
if (conditionsMet()) {
myTable.DataSource = getDataSource();
}
}
private IEnumerable<PersonViewModel> getDataSource() {
List<PersonViewModel> view = new List<PersonViewModel>();
view.Add(new PersonViewModel(new Person() { Uid = Guid.NewGuid(), Name = "Example", Company = "Co" }));
return view;
}
Now you just call myTable.DataBind()
whenever the conditions are met, say when you click a button. When you click a button and need to check which checkboxes are checked, you can use the repeater.Items
property to iterate them, something like this:
private void onValidatePage() {
List<Guid> checks = new List<Guid>();
foreach (RepeaterItem repeatitem in myTable.Items) {
string uid = ((HiddenField)repeatitem.FindControl("uidfield")).Value;
bool value = ((CheckBox)repeatitem.FindControl("valuefield")).Checked;
if (value) {
checks.Add(new Guid(uid));
}
}
// Now "checks" hold all the id's of the checked items
}