Clear grid with static and dynamic columns - c#

I have a grid where I am adding a couple of columns into the template field through the aspx page.
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton ID="lnkBtnDown" runat="server" CommandName="Download" Text="Download"></asp:LinkButton>
<asp:LinkButton ID="LnkBtnMan" runat="server" CommandName="Manual" Text="Manual"
Style="margin-left: 10px"></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
The grid displays search result from a table and there are a few columns that I have to hide, such as the filename column etc, but I do need the data...so I hide them using css styles.
private void generateSearchGrid(DataTable dt)
{
if (dt == null || dt.Rows.Count == 0)
return;
dgvSearchResults.DataSource = dt;
dgvSearchResults.AutoGenerateColumns = false;
BoundField bfName = new BoundField();
bfName.DataField = dt.Columns["OsmProjectName"].ToString();
bfName.HeaderText = "Project Name";
BoundField bfProjID = new BoundField();
bfProjID.DataField = dt.Columns["OsmProjectID"].ToString();
bfProjID.HeaderText = "ID";
BoundField bfProjFile = new BoundField();
bfProjFile.DataField = dt.Columns["OsmProjectFile"].ToString();
bfProjFile.HeaderText = "Project File";
BoundField bfProjManual = new BoundField();
bfProjManual.DataField = dt.Columns["OsmProjectManual"].ToString();
bfProjManual.HeaderText = "Project Manual";
BoundField bfProjType = new BoundField();
bfProjType.DataField = dt.Columns["OsmProjectType"].ToString();
bfProjType.HeaderText = "Project Type";
dgvSearchResults.Columns.Add(bfProjID);
dgvSearchResults.Columns.Add(bfName);
dgvSearchResults.Columns.Add(bfProjType);
// WARNING : Keep these two at the end all the time in the same order.
dgvSearchResults.Columns.Add(bfProjFile);
dgvSearchResults.Columns.Add(bfProjManual);
dgvSearchResults.DataBind();
// Assigning a css where display has been set to none.
bfProjManual.HeaderStyle.CssClass = "hiddenCols";
bfProjID.HeaderStyle.CssClass = "hiddenCols";
bfProjFile.HeaderStyle.CssClass = "hiddenCols";
bfProjManual.ItemStyle.CssClass = "hiddenCols";
bfProjID.ItemStyle.CssClass = "hiddenCols";
bfProjFile.ItemStyle.CssClass = "hiddenCols";
}
At the beginning of every search button click event I refresh the grid by,
dgvSearchResults.DataSource = null;
dgvSearchResults.DataBind();
dgvSearchResults.Columns.Clear();
But this clears all the columns including the ones that I bound in the aspx page..as expected. If I don't clear them, the columns from the search result just keeps piling up.
Is there a way where I can clear only the columns bound dynamically?

If you know how many you've added in the aspx page and how many you add dynamically you could do this.
//if total added in aspx page is 2, first one is in index 0, second in index 1
dgvSearchResults.Columns.RemoveAt(2); // this will remove the 3rd column
dgvSearchResults.Columns.RemoveAt(3); // this will remove the 4th columns
// you can continue till column x

One option is to disable viewstate of dgvSearchResults GridView. In this case, every postback, you need to bind dgvSearchResults with data. If you will not bind, dynamically added columns will be removed automatically (not persisted).
This will happen because in your case, dynamically added data (and also columns) are kept postback to postback in hidden element (viewstate).
So this will become:
private void Page_Load(object sender, EventArgs e)
{
if(IsPostBack) // If postback, then bind GridView with previous search result
{
dgvSearchResults.DataSource = Session["dgvSearchResultsData"];
dgvSearchResults.DataBind();
}
}
private void generateSearchGrid(DataTable dt)
{
// ...
Session["dgvSearchResultsData"] = dt; // Save result into session
dgvSearchResults.DataSource = dt;
// ...
}
ASPX:
<asp:GridView EnableViewState="false"> ... </GridView>

Related

Dynamically created TextBoxes in a Table lost Text value

I have a Table dynamically generated and inside of 2 columns there are TextBoxes. During the postback the Textboxes are always empty even if I fill them.
The table is builted in this way:
protected void ddlScalaTaglie_SelectedIndexChanged(object sender, EventArgs e)
{
DataTable dtRighe = oTab.getScaleTaglieRighe(ddlScalaTaglie.SelectedValue);
//dt is datatable object which holds DB results.
Table tbl = new Table();
tbl.CssClass = "table table-striped table-bordered table-responsive";
TableRow tr;
TableCell tcEU, tcUS, tcUK, tcQty, tcEAN;
Label lbEU, lbUS, lbUK, lbQty, lbEAN;
TextBox tbEU, tbUS, tbUK, tbQty, tbEAN, tbToFocus = null;
foreach (DataRow dr in dtRighe.Rows)
{
tr = new TableRow();
//ean
tcEAN = new TableCell();
tbEAN = new TextBox();
tbEAN.ID = "txtEAN" + dr[0].ToString();
tbEAN.Width = new Unit(100, UnitType.Percentage);
tbEAN.Columns = 15;
tcEAN.Controls.Add(tbEAN);
tr.Controls.Add(tcEAN);
//Qty
tcQty = new TableCell();
tbQty = new TextBox();
tbQty.ID = "txtQty" + dr[0].ToString();
tbQty.TextMode = TextBoxMode.Number;
tcQty.Controls.Add(tbQty);
tr.Controls.Add(tcQty);
tbl.Controls.Add(tr);
}
Session["tbl"] = tbl;
divTaglieRighe.Controls.Add(tbl);
}
When I click the button SAVE, I have to loop throug my table and save all the TextBox.Text...
this is what I wrote:
ArrayList arrScarpaFigli = new ArrayList();
Table tbl = (Table)Session["tbl"];
foreach (TableRow row in tbl.Rows)
{
foreach (TableCell cell in row.Cells)
{
foreach (Control ctrl in cell.Controls)
{
//CONTROL IS TEXBOXT: EXTRACT VALUES//
if (ctrl is TextBox)
{
TextBox txt = (TextBox)ctrl;
arrScarpaFigli.Add(txt.Text);
}
}
}
}
The problem is that, also if I fill the textboxes, in my Text there is always an empty string.
The only moment when I fill the table is on the selectionChange of a Dropdown.
What I'm doing wrong?
Thanks in advance
You have to recreate dynamic controls on every page load to make sure their values are retained after a PostBack. So you need to create a new Method that handles the creation of the Table every time the page is loaded.
protected void Page_Load(object sender, EventArgs e)
{
//always create the controls on every page load if there is a value selected in ddlScalaTaglie
if (!string.IsNullOrEmpty(ddlScalaTaglie.SelectedValue))
{
createTable(ddlScalaTaglie.SelectedValue);
}
}
protected void Button1_Click(object sender, EventArgs e)
{
//use findcontrol to find the Table inside the placeholder
Table tbl = Page.FindControl("divTaglieRighe").FindControl("Table1") as Table;
//loop all rows and cells in the Table
foreach (TableRow row in tbl.Rows)
{
foreach (TableCell cell in row.Cells)
{
foreach (Control ctrl in cell.Controls)
{
//the control is a textbox
if (ctrl is TextBox)
{
//cast the control back to a textbox
TextBox tb = ctrl as TextBox;
//does the checkbox have a value, if so append the label
if (!string.IsNullOrEmpty(tb.Text))
{
Label1.Text += tb.Text + "<br>";
}
}
}
}
}
}
protected void ddlScalaTaglie_SelectedIndexChanged(object sender, EventArgs e)
{
//no need to create the Table dynamically, that will be handled in Page_Load
//this method is just a dummy to trigger a PostBack
//you could remove this method and the OnSelectedIndexChanged from the DropDown
//and just keep the AutoPostBack="true", that will also work
}
private void createTable(string value)
{
DataTable dtRighe = Common.LoadFromDB();
//create a new table WITH id, that is needed for findcontrol
Table tbl = new Table();
tbl.ID = "Table1";
//loop all rows in the datatable
foreach (DataRow dr in dtRighe.Rows)
{
TableRow tr = new TableRow();
//ean
TableCell tcEAN = new TableCell();
TextBox tbEAN = new TextBox();
tbEAN.ID = "txtEAN" + dr[0].ToString();
tbEAN.Width = new Unit(100, UnitType.Percentage);
tbEAN.Columns = 15;
tcEAN.Controls.Add(tbEAN);
tr.Controls.Add(tcEAN);
//Qty
TableCell tcQty = new TableCell();
TextBox tbQty = new TextBox();
tbQty.ID = "txtQty" + dr[0].ToString();
tbQty.TextMode = TextBoxMode.Number;
tcQty.Controls.Add(tbQty);
tr.Controls.Add(tcQty);
tbl.Controls.Add(tr);
}
//add the table to the placeholder
divTaglieRighe.Controls.Add(tbl);
}
The aspx to make the example complete
<asp:DropDownList ID="ddlScalaTaglie" runat="server" OnSelectedIndexChanged="ddlScalaTaglie_SelectedIndexChanged" AutoPostBack="true">
<asp:ListItem Text="Select..." Value=""></asp:ListItem>
<asp:ListItem Text="Option 1" Value="1"></asp:ListItem>
<asp:ListItem Text="Option 2" Value="2"></asp:ListItem>
</asp:DropDownList>
<br />
<br />
<asp:PlaceHolder ID="divTaglieRighe" runat="server"></asp:PlaceHolder>
<br />
<br />
<asp:Button ID="Button1" runat="server" Text="Save" OnClick="Button1_Click" />
<br />
<br />
<asp:Label ID="Label1" runat="server" Text=""></asp:Label>
Storing an instance of Table control in Session is a terrible idea and is just plain wrong. Controls belong to their parent page - they should be added to it as soon as they are created and they should die with their parent page.
The thing with dynamically created controls in ASP.NET is that you have to store an indicator of the fact that they were created (together with relevant information needed to create them again) and recreate them on all subsequent postbacks - no later than in Page_Load. Only then these controls will have the chance of getting their values from Request and you will have the chance of obtaining these values from controls.
In your code, the instance of Table stored in Session (together with all its rows, cells and textboxes) will never reflect any client-side data changes, nor will it belong to Pages that will be created to process subsequent postback requests.
Update
The important fact to understand here is that, after processing the postback caused by ddlScalaTaglie change and returning hew html to the client, the page instance is gone. On next request a new instance of your page is created - and it does not know anything about the fact that the previous instance had table added to its control tree. It is your code in Page_Load that must discover that the form must have this table, and create the table in exactly the same way it was created the first time - with rows, cells and textboxes with exactly the same IDs.
Then, after you add this newly created table to divTaglieRighe.Controls, the textboxes will be able to extract their client-side values from Request.Form collection.
Make sure the textbox has a "name" for the post back to the controller.
If it does not it grabs a null for the parameter.
Check Request.Form for data returned to controller.
You've created a Table called tbl and added two TextBox, then you store Table control in session Session["tbl"] and added to divTaglieRighe control. Finally you are trying to get TextBox data from your session Session["tbl"] table not the ViewState control that added in divTaglieRighe control. You have to get data from you Table tbl control that added in divTaglieRighe control.

How to select a row in a DataGridView programmatically AND trigger DataGridView.SelectionChanged event?

For the life of me I cannot seem to figure this out. I have a long DataGridView (that does not allow MultiSelect) and when a user commits a change to the data, the data from the grid is purged and redrawn (because changes can affect multiple rows, this was the simpler approach). However, when I try to select the row programmatically, it does not also fire the DataGridView.SelectionChanged event, which I use to display data from an array which is correlated to the DataGridView current cell index. When doMagicStuff executes, the values for the wrong index (specifically, index 0) is show.
private void doMagicStuff()
{
int selRow = myDGV.CurrentCell.RowIndex;
myDGV.Rows.Clear();
/*Perform Task, Redraw data*/
myDGV.CurrentCell = myDGV[selRow, 0];
}
private void myDGV_SelectionChanged(object sender, EventArgs e)
{
Label1.Text = myDisplayValue1[myDGV.CurrentCell.RowIndex];
Label2.Text = myDisplayValue2[myDGV.CurrentCell.RowIndex];
TextBox1.Text = myEditValue1[myDGV.CurrentCell.RowIndex];
TextBox2.Text = myEditValue2[myDGV.CurrentCell.RowIndex];
}
Make sure that your client settings and OnSelectedIndexChanged is set like so: (ASP.NET AJAX)
.aspx page
<telerik:RadGrid ID="Grid1" runat="server" OnSelectedIndexChanged="Grid1_SelectedIndexChanged" OnItemDataBound="Grid1_ItemDataBound" OnPreRender="Grid1_PreRender">
<ClientSettings EnablePostBackOnRowClick="true">
<Selecting AllowRowSelect="true"></Selecting>
</ClientSettings>
</telerik:RadGrid>
aspx.cs page
protected void Grid1_SelectedIndexChanged(object sender, EventArgs e)
{
string value = null;
foreach(GridDataItem item in Grid1.SelectedItems)
{
//column name is in doub quotes
value = item["Name"].Text;
}
}
Add a button click to the form to test the selected values in the DataGridView.. double click that button then paste this code in there
foreach (DataGridViewRow row in myDGV.SelectedRows)
{
Label1.Text = //This should be hard coded the only thing that should change dynamically is the TextBox Values
Label2.Text = //This should be hard coded the only thing that should change dynamically is the TextBox Values
TextBox1.Text = row.Cells[0].Value.ToString();//change the 0 or 1 to fit your column Index position
TextBox2.Text = row.Cells[2].Value.ToString();
}
also if you have 4 columns and 4 text boxes then you will assign all of the textbox.Text values within the foreach loop just follow the pattern and increase the index by 1 so 2 textboxes means row.Cells[0] is the first column row.Cells[1] is the second column ...etc

ASP TextBox extra values after postback

In summary: I'm saving grid id and row number to some hidden textboxes inside a GridView so I can update the session data via jQuery. After a drag and drop operation on the GridView, one of the textboxes holds different data than it should. Does anyone know why this might be?
Edit: solved by doing the databinding in Page_PreRender instead of Page_Load.
I'm trying to build a page with 2 draggable and sortable GridViews. This is a 'teach myself jQuery in preparation for using those methods on production pages' kind of project. When a row is dragged and dropped, it calls a postback to update the underlying datasets and rebind the grids. Users should be able to reorder the gridviews and also drag rows from one to the other. I get the feeling that I'm making it way harder than it should be, but that's not my question.
To make the postbacks work, I'm creating 2 hidden textboxes that store the grid id and row number on each row. jQuery uses those as parameters to pass to the code-behind via a PageMethods call. All of that works, the first time.
If I try to do a drag-and-drop on a row I already dragged and dropped once, the row number textbox.text field becomes x,x instead of x like the other rows. For instance, dragging row 1 somewhere makes row 1's TextBox.Text become 1,1. I've verified that in RowDataBound the number is 1 and at Page_Unload it's 1,1. Why is this?
Javascript:
<script type="text/javascript">
$(document).ready(function () {
$( ".draggable" ).draggable({
helper: "clone",
stack: ".draggable",
snapto: ".droppable",
create: function(event, ui){
var GridID = $(this).find(".gridid").attr("value");
$(this).data("source",GridID);
var RowID = $(this).find(".rowindex").attr("value");
$(this).data("rowid",RowID);
}
});
$( ".droppable" ).droppable({
tolerance: "intersect",
greedy: true,
create: function(event, ui){
var GridID = $(this).find(".gridid").attr("value");
$(this).data("source",GridID);
var RowID = $(this).find(".rowindex").attr("value");
$(this).data("rowid",RowID);
},
drop: function(event, ui){
var SourceGrid = ui.draggable.data("source");
var SourceRow = ui.draggable.data("rowid");
var DestGrid = $(this).data("source");
var DestRow = $(this).data("rowid");
PageMethods.MoveRow(SourceGrid, DestGrid, SourceRow, DestRow);
__doPostBack('','');
}
});
});
</script>
ASP:
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolderMain" runat="Server">
<asp:GridView ID="gvSource" runat="server" ShowFooter="true"
OnRowDataBound="gvSource_RowDataBound">
</asp:GridView>
<asp:GridView ID="gvDest" runat="server" ShowFooter="true"
OnRowDataBound="gvSource_RowDataBound">
</asp:GridView>
Code-Behind (minus the DataBinding and fetching parts):
protected void gvSource_RowDataBound(object sender, GridViewRowEventArgs e) {
TextBox gridid = new TextBox();
gridid.Text = ((GridView)sender).ClientID;
gridid.CssClass = "gridid hidden";
TextBox rowindex = new TextBox();
switch (e.Row.RowType) {
case DataControlRowType.DataRow:
rowindex.Text = e.Row.RowIndex.ToString();
break;
case DataControlRowType.Header:
rowindex.Text = "0";
break;
case DataControlRowType.Footer:
rowindex.Text = ((DataTable)((GridView)sender).DataSource).Rows.Count.ToString();
break;
default:
rowindex.Text = "null";
break;
}
rowindex.CssClass = "rowindex hidden";
e.Row.Cells[0].Controls.Add(gridid);
e.Row.Cells[0].Controls.Add(rowindex);
}
[WebMethod]
public static string MoveRow(string _sourcegrid, string _destgrid, string _sourcerow, string _destrow) {
HttpContext ctx = HttpContext.Current;
DataTable dtsrc = _sourcegrid == ((DataTable)ctx.Session["dtFrom"]).TableName ? (DataTable)ctx.Session["dtFrom"] : (DataTable)ctx.Session["dtTo"];
DataTable dtdest = _destgrid == ((DataTable)ctx.Session["dtFrom"]).TableName ? (DataTable)ctx.Session["dtFrom"] : (DataTable)ctx.Session["dtTo"];
DataRow row = dtsrc.Rows[Convert.ToInt32(_sourcerow)];
DataRow newrow = dtdest.NewRow();
int newrowpos = Convert.ToInt32(_destrow);
newrow.ItemArray = row.ItemArray;
dtsrc.Rows.Remove(row);
dtdest.Rows.InsertAt(newrow, newrowpos);
return "1";
}
CSS-wise, all rows have CssClass="droppable draggable". Headers and footers are just droppable. I left off some error checking code for brevity.
edit: added a summary, and I wanted to add that I've looked through SO and found only topics about a TextBox losing its data, not changing it.
The problem had something to do with binding the data in Page_Load. It looked like
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) {
GetData(); //Database fetch saves 2 DataTables to session variables
}
gvSource.DataSource = (DataTable)Session["dtFrom"];
gvSource.DataBind();
gvDest.DataSource = (DataTable)Session["dtTo"];
gvDest.DataBind();
}
and it failed. Made it
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) {
GetData(); //Database fetch
}
}
protected void Page_PreRender(object sender, EventArgs e) {
gvSource.DataSource = (DataTable)Session["dtFrom"];
gvSource.DataBind();
gvDest.DataSource = (DataTable)Session["dtTo"];
gvDest.DataBind();
}
and it worked. Why it worked is still open for debate. Thanks guys for helping this long-time lurker with basic SO usage and etiquette.

gridview RowUpdating event using asp:Command Field type button

I am using asp command field type button for editing gridview row.
A row is suppose to be not showing in the grid whenever user update a record. The ShowAllClasses() method is suppose to fetch records from sql db excluding recently updated row.
Now behavior of "Update" Command Field Button.
Localhost:
As I click on the button it hides the row (means binding is done again). In this case record gets updated once. (as required)
On deployed application:
Upon user click the row doesn't hide and user is able to click many times on the button (as if function is not working). But as user stops clicking button, after a minor delay, editing mode of gridview goes away and binding after update is fired.
Bad thing is that the sql table updates each time button is clicked.
Help me how I can fix this.
Here is code I am using
Markup of command field inside GridView1:
<asp:CommandField ButtonType="Button" HeaderText="Edit/Update" ShowEditButton="True"
ShowHeader="True" UpdateText="Set Class" ItemStyle-HorizontalAlign="Center" />
GridView RowUpdating Event:
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
lblError.Text = string.Empty;
int iTutorID = Convert.ToInt32(Session["EID"]);
DropDownList ddlTime = GridView1.Rows[e.RowIndex].FindControl("ddlClassTime") as DropDownList;
string sClassTime = ddlTime.SelectedItem.Text;
HiddenField hf = GridView1.Rows[e.RowIndex].FindControl("sIdHidden") as HiddenField;
int iSID = Convert.ToInt32(hf.Value);
hf = GridView1.Rows[e.RowIndex].FindControl("cIdHidden") as HiddenField;
int iCID = Convert.ToInt32(hf.Value);
hf = GridView1.Rows[e.RowIndex].FindControl("hfClassTime") as HiddenField;
string sOriginalClassTime = hf.Value.ToString();
if (sOriginalClassTime.Length < 8)
sOriginalClassTime = "0" + sOriginalClassTime;
DropDownList ddlDate = GridView1.Rows[e.RowIndex].FindControl("ddlClassDate") as DropDownList;
DateTime dNewDate = Convert.ToDateTime(ddlDate.SelectedValue);
Label lblLesson = GridView1.Rows[e.RowIndex].FindControl("lblLesson") as Label;
string sLesson = lblLesson.Text;
DateTime dClassDate = Convert.ToDateTime(ddlAdvDay.SelectedValue);
//cond: same date and same time set
if (sOriginalClassTime == sClassTime && dNewDate == dClassDate.Date)
{
//show error
lblError.Text = "Same class date and time cannot be set as Advanced class";
return;
}
lblError.Text = string.Empty;
BLClass blClass = new BLClass();
//1. insert in makeup table today's class
//2. insert in classdetails table
//1. insert in makeup table with today's date
blClass.InsertAdvancedClass(iTutorID, iSID, iCID, dClassDate, dNewDate);
//2. insert in classdetails table
blClass.InsertClassDetails(iTutorID, iSID, iCID, dNewDate, sClassTime, "Advanced", sLesson);
GridView1.EditIndex = -1;
ShowAllClasses();
}
Method for Binding Grid with DataSource:
private void ShowAllClasses()
{
lblError.Text = string.Empty;
int iTutorID = Convert.ToInt32(Session["EID"]);
BLClass blClass = new BLClass();
DateTime dClassDate = Convert.ToDateTime(ddlAdvDay.SelectedValue);
DataTable dtClass = blClass.GetAdvancedClasses(iTutorID, dClassDate.Date);
//temp method for date display format
FixDateFormat(dtClass);
dtClass.AcceptChanges();
GridView1.DataSource = dtClass;
GridView1.DataBind();
}
Disable the update link button at the end of the row updating event. Then in the row editing event set the control to active. This would keep the user from clicking the button twice. Sounds like a bad connection to production server.
this.mybutton.enabled = false:

How to find a control recursively in ASP.NET

There are lots of examples on this, and I'm pretty sound with the concept of using recursion to find the control. Once the control has been found on postback, it can be interacted with, etc.
I have an empty asp:table in my HTML markup:
<asp:Table ID="editDataTable" runat="server">
</asp:Table>
And on Page_Load the table is populated with many rows and many columns (I am quite proud that I figured that out). Inside some of the table cells there is a <asp:TextBox />.
You've guessed it, I need to get the value of these text boxes!
(I've got the code for recursion and checked it, and it seems good.)
My table has two columns. The left one contains titles like "Company Name, Telephone", etc. and the right column contains text boxes with its respective title's value. So a user can edit the text box (if the telephone number has change for example) and submit the changes.
Obviously the rows are dynamically added depending on the user.
The problem I'm having is: You need to ADD the control to the page when populating the table. Something along the lines of:
myTable.Control.Add(new TextBox());
In my case, my Table is called editDataTable. So in my code where I add the Rows, I've added the control too, as follows.
for (int i = 0; i < rowCount; i++)
{
editDataTable.Rows.Add(tblRow[j]); // This is where I add the ROW to my sexy table
editDataTable.Controls.Add(new TextBox()); // This is where I add the control
}
Those awake amongst you will know that you can't add a text box control to a table!
So finally, my questions are:
How do I add the control for The Text Boxes in my table?
Where do I add them?
Is there any extra advice to help me fulfill my quest of retrieving the text values of my dynamically added text boxes?
Here's my recursive code just in case you were curious:
private void getControls(Control parent)
{
foreach (Control c in parent.Controls)
{
if (c is TextBox && c.ID == null)
{
//Stuff
}
if (c.Controls.Count > 0)
{
getControls(c);
}
}
}
Here is an example of building a dynamic table in ASP.NET during PageLoad, and reading in the values through a postback. Since the table is dynamic, it will NOT be rebuilt when the page is postback to the server. If you want to rebuild the table, you'll need to render it again and use the values you pull in from Request.Form to re-populate it.
HTML Markup
<asp:Table ID="editDataTable" runat="server">
</asp:Table>
<asp:Button runat="server" Text="Submit" OnClick="Submit_Click" />
Code Markup
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
string[] dynamicTable = { "First Name", "Last Name", "Address", "Phone" };
foreach (string s in dynamicTable)
{
TableRow row = new TableRow();
// Add First Cell with Text to Row
row.Cells.Add(new TableCell() { Text = s });
// Create Second Cell
TableCell textBoxCell = new TableCell();
// Add Textbox Control to Second Cell
textBoxCell.Controls.Add(new TextBox() { ID = "Dynamic_" + s.Replace(" ","_") });
// Add Second Cell to Row
row.Cells.Add(textBoxCell);
// Add New Row to Table
editDataTable.Rows.Add(row);
}
}
}
protected void Submit_Click(object sender, EventArgs e)
{
for (int i = 0; i < Request.Form.Count; i++)
{
string key = Request.Form.GetKey(i);
if (key.Contains("Dynamic_"))
{
Response.Write("<p><strong>" + (key.Remove(0,8)).Replace("_"," ") + "</strong> :: " + Request.Form[i] + "</p>");
}
}
}
You need to add a TableCell to the TableRow.Cells collection, and add the TextBox to the TableCell.Controls collection:
TableCell cell = new TableCell();
cell.Controls = new TextBox();
tblRow[j].Cells.Add(cell);
editDataTable.Rows.Add(tblRow[j]);
The most direct way to access the textboxes is to keep them all in a list:
List<TextBox> textBoxes = new List<TextBox>();
and replace cell.Controls = new TextBox(); above with this:
TextBox tb = new TextBox();
textBoxes.Add(tb);
cell.Controls = tb;
And then you can iterate through the textBoxes afterward without having to search for them in a tree.

Categories

Resources