Dynamically added TableRows not in Rows collection on Postback - c#

I've added TableRows via code-behind to a table. The rows render on the page, but on PostBack, the rows are no longer part of the collection. What is the trick to get these rows to persist so that I can use them on PostBack?
.ascx
<asp:Table id="OrderItemsTable" runat="server">
.ascx.cs
TableRow itemRow = new TableRow();
// Ticket Quantity
TableCell cell1 = new TableCell();
cell1.Attributes.Add("align", "center");
TextBox ticket1QuantityTextBox = new TextBox();
ticket1QuantityTextBox.Width = Unit.Pixel(30);
ticket1QuantityTextBox.MaxLength = 3;
ticket1QuantityTextBox.Attributes.Add("class", "OrderItemTicketQuantityTB");
ticket1QuantityTextBox.Text = item.Quantity.ToString();
cell1.Controls.Add(ticket1QuantityTextBox);
itemRow.Cells.Add(cell1);
...
OrderItemsTable.Rows.Add(itemRow);

You need to contruct dynamic controls on the Page_Init event. Are you perhaps doing this in Page_Load or elsewhere. If they are added later than Page_Init then they don't participate in ViewState which will cause problems.

Yes, you need to construct the control tree with your dynamic controls in Page_Int event so that ASP.NET can load the ViewState data later into Page Control tree (which you will need to access the values from TextBox)
On a side not you should use Dynamic control only when the type of control is dynamic. Else you can achive the same using Repeater and listview
Truely Understanding Dynamic Controls
And here is the alternative to using Dynamic controls
ASP.NET: Alternatives to Dynamic Controls - Part 1

Related

Dynamic Hyperlink is not getting visible in gridview

I am trying to show dynamic hyperlink on each row of a dynamic gridview using below code but it is not showing the hyperlink.
gvdates.DataSource = xyz;
var m = tool.ToolsID;
HyperLink hp = new HyperLink();
hp.Text = e.Row.Cells[i].Text;
hp.NavigateUrl = "~/OutageInfo.aspx?name=m;" + hp.Text;
e.Row.Cells[i].Controls.Add(hp);
gvdates.DataBind();
e.Row.Cells[i].Controls.Add(gvdates);
You should create dynamic controls in RowCreated instead of RowDataBound because this event gets fired on every postback whereas RowDataBound only will fire when the GridView gets databound to it's DataSource.
Dynamically created controls must be recreated on every postback with the same ID as before, then they retain their values in the ViewState and events will fire correctly.
So you should create them in RowCreated and "fill" them in RowDataBound(f.e. the HyperLink's NavigateUrl if it's from the datasource).
However, you should add dynamic controls after you have databound the GridView. So this seems to be pointless (whatever e is):
e.Row.Cells[i].Controls.Add(hp);
gvdates.DataBind();

Gridview returning empty even when there is data. I want to use data in the gridview to update another database

I have a webform that the user captures data. This data affects other data that is in a Gridview. I wanted to right a DetailsView type control that makes an Update button visible if data is change in textboxes and drop downs that would require a master data update.
I have a gridview on the form and when the user click on update I wanted to update all the rows in the databases using the primary key OrderId which is on the Gridview.
If I put the code being each textbox and dropdown box and that calls a routine called DoUpdate then this works. However it is a little slow since each change forces an update, so I thought it would be better to rather have an update button appear, and then the user can click that to do the update.
When the routine is called from the button routine though the gridview has no rows. I assume I either need to findcontrol (gridview) or something but have not idea what to find it in.
Here is the code that works when called in a behind button event, but the gridview returns row count 0 when called as part of the code behind button:
List<string> _OrderIds = new List<string>();
foreach (GridViewRow gvr in gvOrderLines.Rows)
{
Label myOrderIDLablel = (Label)gvr.FindControl("lblOrderID"); //find control since it is a template field
_OrderIds.Add(myOrderIDLablel.Text);
}
The gridview is defined in the ASP page
<asp:GridView ID="gvOrderLines" runat="server" AutoGenerateColumns="False"
DataSourceID="odsOrderDetail"
Per my comment above you may want to do something like:
List<string> _OrderIds = new List<string>();
DataTable table = gvOrderLines.DataSource as DataTable;
foreach (GridViewRow gvr in table.Rows)
{
Label myOrderIDLablel = (Label)gvr.FindControl("lblOrderID"); //find control since it is a template field
_OrderIds.Add(myOrderIDLablel.Text);
}
I hope this get you headed in the right direction.

Is there a textboxlist control available somewhere?

There are ASP controls such as radiobuttonlist and checkboxlist and you can databind them to a database query. It's great for creating dynamic lists with user interaction. What I'm trying to do is generate a list of textboxes in the same fashion. A list of textboxes that behave the same way.
The object is to have a checkboxlist that is generated via datasource/database. When the user is finished selecting items from this list, they click a button. That list hides (using jquery) and a new list is created based on their selections. However, the new list is now a list of their selections accompanied by an empty textbox. The user fills in the textboxes for each entry and submits again which commits it to a database.
SO:
checkbox - description
checkbox - description
checkbox - description
checkbox - description
Becomes:
Description - Textbox
Description - Textbox
The reason that I'm looking for a list-type control is so that I can ultimately loop through it for submission to the database using linq. Does that make sense? My real question is if there is a control like this yet. I gave the full description in case someone has any other ideas, short of creating a custom control.
There's nothing out of the box that does what you describe no. But you can still loop through controls. I would put your form controls inside of an asp:Panel or a div with runat="server" and use something like the following code to cycle through them as you described.
foreach(Control ctl in myPanel.Controls)
{
//check control type and handle
if (ctl is TextBox)
{
//handle the control and its value here
}
}
asp:ListBox has a property named SelectionMode, which can be set to SelectionMode="Multiple" and allows you to select items you want. This is not exactly what you need but it's a simple solution.
After the selection is made in checkboxlist, make a postback to server. Here create a datatable with two columns (description & text). For every selected item in the checkboxlist add a row to this table and bind it to a gridview control. Here 'text' column will be always empty. Configure the gridview to use template column with a textbox in the itemtemplate

Insert TextBoxes into a Repeater dynamically and retrieve their value

I have a Repeater bound from SQL, containing a mixture of editable and read-only elements. When you click the "Edit" button on a row, the editable portions should convert to textboxes, and when you click "Update", it should save your changes.
Here's a (very) simplified version of the Edit and Update buttons' OnClick code:
switch(commandName)
{
case "Edit":
Label1.Visible = false; //hide read-only version
PlaceHolder1.Visible = true; //show editing version
//Dict1 is Dictionary<string, string> in this example.
foreach (var key in Dict1)
{
//insert a TextBox dynamically into the PlaceHolder
PlaceHolder1.Controls.Add(new TextBox
{
ID = "txt" + key,
Text = Dict1[key]
});
}
break;
case "Update":
//retrieve user input from dynamically-added TextBoxes
foreach (var TextBox1 in PlaceHolder1.Controls.Where(c => c.ID.StartsWith("txt")))
{
doStuff(TextBox1);
}
Label1.Visible = true; //show read-only version
PlaceHolder1.Visible = false; //hide editing version
break;
}
The problem is that my dynamically-added TextBoxes aren't there when the page posts back. I've examined PlaceHolder1.Controls in the debugger, and there are no TextBoxes in it. PlaceHolder1 itself is inside a Repeater, but I'm not rebinding the Repeater on PostBack.
I've considered using raw HTML in place of TextBox controls and pulling the values out of Request.Form, but that feels hackish to me. How can I make the dynamically-added TextBoxes persistent across postbacks?
EDIT:
There are some complications here that it's hard to show without a ton of sample code. Here are the big ones:
Each cell in the repeater can have a mixture of read-only and editable text (i.e. dynamically-inserted Labels and TextBoxes)
I don't know how many editable regions are going to be in each cell. The original text might look like blah blah #A1# blah blah #A2# blah..., and I would have to insert replacement text in place of #A1#, #A2#, etc. In edit mode, only that replacement text is editable.
When you add controls dynamically, they aren't preserved across postbacks. You have to add them to the page again after postback. I usually do it in Page_Load. Then, once they are added, their postback states will be restored correctly later in the ASP.NET page life cycle.
So,
Dynamic controls must be added each time the page is loaded,
but once you add them, ASP.NET restores their state correctly.
Hope this helps!
One possible answer would be to have the TEXTBOX pre-defined in the ITEM TEMPLATE, and then just set its' visiblity for the given row on the click event.
A second possibility would be to refactor the repeater to utilize the GRIDVIEW control instead. It supports editable templates out of the box.
Anyways, what's happening, is that since those controls are added dynamically, they're not getting recreated on the next postback. On the postback, you'll need to re-create the controls if you want to access them. BUT, don't forget that the value IS stored in the form collection:
myval = request.form["txt" + key];

Bind gridview on user control

I have a 2 usercontrol on a aspx page. 1 control is having search creteria and search button and 2nd usercontrol is having gridview.
How do I bind gridview when user enter creteria and click on search button.
The click event need to be bubbled up to the aspx page and then passed to the gridview usercontrol. See the following link how to bubble events.
http://odetocode.com/code/94.aspx
Considering the 1st UserControl produces a DataTable. Specify a Property in 2nd UserControl which accepts the datatable and bind it to the grid inside the control.
Control2:
public datatable Result{get;set;}
Private void SetGrid()
{
datagrid1.datasource=Result;
datagrid1.databind();
}
Control1:
Datatable dt=SearchResult();
Control2.Result=dt;
In the second user control in .ascx page you can Reference first user control
like as
<%# Reference Control="first user control names comes here" %>
In second user control page load event you can find object of first user control using below mentioed ways:
UserControls_UCFirst uc1 = (UserControls_UCFirst)this.Parent.FindControl("UCFirst1");
then you can find search criteria objects (TextBox, DropDownList, etc..) of first user control.
TextBox txt = (TextBox)(uc1.FindControl("txtName"));
Through above process you can bind grid view.
Hope it will helps.
First Get the searched Results in a DataTable, and Stored the DataTable in a ViewState. And then set the DataTable in a ViewState as datasource of the GridView.
Like this,
GridView1.DataSource = ViewState["DataTable1"];
GridView1.DataBind();
I hope this will help u.

Categories

Resources