AJAX toolkit Accordion doesn't work when published - c#

I'm using an AJAX accordion from the AJAX control toolkit to display a dynamic list of items, which are pulled from a database. I generate the entire accordion from code behind. This works without problems when testing it locally, but when i publish it online, the accordion shows the first item but doesn't do anything else when clicked, basically not responding to anything. There are also links to other pages inside the accordionpane contents, and these do work.
For aspx i'm using a masterpage with inside it a toolkitscriptmanager:
<asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server EnablePartialRendering="true">
</asp:ToolkitScriptManager>
and in the content i also added a scriptmanagerproxy in the hopes that that would solve the problem, but it didn't.
the empty accordion is like this:
<asp:accordion ID="Accordion1" runat="server"
HeaderCssClass="Header" ContentCssClass="Contents"
Font-Names="Verdana" Font-Size="10"
BorderColor="#000000" BorderStyle="Solid" BorderWidth="1"
FramesPerSecond="100" FadeTransitions="true"
TransitionDuration="500">
</asp:accordion>
This is my current code to generate the accordion:
public void getRequests()
{
DataTable requests = getRequests();
if (requests.Rows.Count == 0)
{
return;
}
for (int i = 0; i < requests.Rows.Count; i++)
{
DataTable makers = getInformationByRequest();
AjaxControlToolkit.AccordionPane pane1 = new AjaxControlToolkit.AccordionPane();
pane1.ID = "pane" + i;
Table table = new Table();
table.Width = Unit.Percentage(100);
TableRow row = new TableRow();
row.CssClass = "Header";
for (int j = 0; j < 4; j++)
{
Create panel head with information
}
table.Rows.Add(row);
pane1.HeaderContainer.Controls.Add(table);
Table table1 = new Table();
table1.Width = Unit.Percentage(100);
TableRow rowhead = new TableRow();
rowhead.CssClass = "Contents";
TableCell cellName = new TableCell();
cellName.Text = "Bedrijf naam";
TableCell cellStatus = new TableCell();
cellStatus.Text = "Request status";
TableCell cellAction = new TableCell();
cellAction.Text = "Actie";
rowhead.Cells.Add(cellName);
rowhead.Cells.Add(cellStatus);
rowhead.Cells.Add(cellAction);
table1.Rows.Add(rowhead);
for (int j = 0; j < makers.Rows.Count; j++)
{
TableRow row1 = new TableRow();
if (makers.Rows.Count != 0)
{
//method to create table1
}
pane1.ContentContainer.Controls.Add(table1);
}
Accordion1.Panes.Add(pane1);
}
This works without any problems when debugging, as i've said.
Any help is greatly appreciated.
EDIT:
I solved it by using this:
http://geekswithblogs.net/lorint/archive/2007/03/28/110161.aspx
Thanks to henk mollema for putting me on the right track.

Related

how to get the value of dynamically populated controls

I have a div Conatining a Panel in aspx page
<div id="divNameofParticipants" runat="server">
<asp:Panel ID="panelNameofParticipants" runat="server">
</asp:Panel>
</div>
I am populating the panel dynamically from codebehind with the following code:
void btnSubmitCountParticipant_Click(object sender, EventArgs e)
{
StringBuilder sbparticipantName=new StringBuilder();
try
{
int numberofparticipants = Convert.ToInt32(drpNoofparticipants.SelectedValue);
ViewState["numberofparticipants"] = numberofparticipants;
Table tableparticipantName = new Table();
int rowcount = 1;
int columnCount = numberofparticipants;
for (int i = 0; i < rowcount; i++)
{
TableRow row = new TableRow();
for (int j = 0; j < columnCount; j++)
{
TableCell cell = new TableCell();
TextBox txtNameofParticipant = new TextBox();
txtNameofParticipant.ID = "txtNameofParticipant" + Convert.ToString(i);
cell.ID = "cell" + Convert.ToString(i);
cell.Controls.Add(txtNameofParticipant);
row.Cells.Add(cell);
}
tableparticipantName.Rows.Add(row);
panelNameofParticipants.Controls.Add(tableparticipantName);
}
}
catch(Exception ex)
{
}
}
Now I want to access the value of these dynamically generated textbox in the codebehind.for which i my code is as under:
public void CreateControls()
{
try
{
//String test1 = test.Value;
List<string> listParticipantName = new List<string>();
if (ViewState["numberofparticipants"] != null)
{
int numberofparticipants = Convert.ToInt32(ViewState["numberofparticipants"]);
for (int i = 0; i < numberofparticipants; i++)
{
string findcontrol = "txtNameofParticipant" + i;
TextBox txtParticipantName = (TextBox)panelNameofParticipants.FindControl(findcontrol);
listParticipantName.Add(txtParticipantName.Text);
}
}
}
catch (Exception ex)
{
}
}
but I am not able to get the values in codebehind.
TextBox txtParticipantName = (TextBox)panelNameofParticipants.FindControl(findcontrol);
the above code is not able to find the control and its always giving null.what am i doing wrong.i recreated the controls in page load also since postback is stateless but still no success.
Thanks in Advance
You need to create dynamic controls in PreInit not in OnLoad. See documentation here: https://msdn.microsoft.com/en-us/library/ms178472.aspx
Re/Creating the controls on page load will cause the ViewState not to be bound to the controls because viewstate binding happens before OnLoad.
As mentioned by other people. To create dynamic controls your need to do this for every postback and at the right time. To render dynamic controls, use the Preinit event. I suggest that your have a look at https://msdn.microsoft.com/en-us/library/ms178472(v=vs.80).aspx to learn more about this.
MSDN - PreInit:
Use this event for the following:
Check the IsPostBack property to determine whether this is the first time the page is being processed.
Create or re-create dynamic controls.
Set a master page dynamically.
Set the Theme property dynamically.
Read or set profile property values.
NoteNote If the request is a postback, the values of the controls have not yet been restored from view state. If you set a control property at this stage, its value might be overwritten in the next event.
The next interesting event is Preload that states:
MSDN - PreLoad
Use this event if you need to perform processing on your page or control before the Load event.
After the Page raises this event, it loads view state for itself and all controls, and then processes any postback data included with the Request instance.
Meaning that in the next event Load (Page_Load) the viewstate should be loaded, so here you should effectively be able to check your values.
You also need to make sure that view state is enabled and the easiest is probably in the page level directive:
<%#Page EnableViewState="True" %>
Take a look at the article https://msdn.microsoft.com/en-us/library/ms972976.aspx2 that goes more into the depth of all this
Note
If your problem is that you need to create controls dynamically on a button click, and there will be many controls created, you should probably turn to jQuery ajax and use the attribute [WebMethod] on a public function in your code behind. Creating dynamic controls and maintaining the ViewState is quite costly, so i really recommend this, for a better user experience.
If you use a DataPresentation control like asp:GridView it will be much easier.
Markup
<asp:GridView ID="ParticipantsGrid" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:TemplateField HeaderText="Participants">
<ItemTemplate>
<asp:TextBox ID="txtNameofParticipant" runat="server"
Text='<%# Container.DataItem %>'>
</asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Code-behind
protected void btnSubmitCountParticipant_Click(object sender, EventArgs e)
{
try
{
var selectedParticipantCount = Convert.ToInt32(drpNoofparticipants.SelectedValue);
var items = Enumerable.Repeat(string.Empty, selectedParticipantCount).ToList();
ParticipantsGrid.DataSource = items;
ParticipantsGrid.DataBind();
}
catch (Exception ex)
{ }
}
public void CreateControls()
{
try
{
var participants = ParticipantsGrid.Rows
.Cast<GridViewRow>()
.Select(row => ((TextBox)row.FindControl("txtNameofParticipant")).Text)
.ToList();
}
catch (Exception ex)
{ }
}
I think you are doing that correctly. In asp.net webforms, there are lots of times that you will experienced strange things that are happening. Especially with the presence of ViewState. First we need to troubleshoot our code and try different tests and approaches. That will be my advise for you, pleas use this code and debug if what is really happening:
void btnSubmitCountParticipant_Click(object sender, EventArgs e)
{
StringBuilder sbparticipantName=new StringBuilder();
try
{
int numberofparticipants = Convert.ToInt32(drpNoofparticipants.SelectedValue);
ViewState["numberofparticipants"] = numberofparticipants;
Table tableparticipantName = new Table();
int rowcount = 1;
int columnCount = numberofparticipants;
TableRow row = new TableRow();
TableCell cell = new TableCell();
TextBox txtNameofParticipant = new TextBox();
txtNameofParticipant.ID = "NameTest";
txtNameofParticipant.Text = "This is a textbox";
cell.ID = "cellTest";
cell.Controls.Add(txtNameofParticipant);
row.Cells.Add(cell);
tableparticipantName.Rows.Add(row);
panelNameofParticipants.Controls.Add(tableparticipantName);
}
catch(Exception ex)
{ // please put a breakpoint here, so that we'll know if something occurs,
}
}
public void CreateControls()
{
try
{
//String test1 = test.Value;
List<string> listParticipantName = new List<string>();
//if (ViewState["numberofparticipants"] != null)
//{
string findcontrol = "NameTest";
TextBox txtParticipantName = (TextBox)panelNameofParticipants.Controls["NameText"];
//check if get what we want.
listParticipantName.Add(txtParticipantName.Text);
//}
}
catch (Exception ex)
{// please put a breakpoint here, so that we'll know if something occurs,
}
}
Dynamic controls need to be recreated on every post-back. The easiest way to achieve that in your code would be to cache the control structure and repopulate it. This how it can be done:
void btnSubmitCountParticipant_Click(object sender, EventArgs e)
{
StringBuilder sbparticipantName=new StringBuilder();
Panel p1 = new Panel();
try
{
int numberofparticipants = Convert.ToInt32(drpNoofparticipants.SelectedValue);
ViewState["numberofparticipants"] = numberofparticipants;
Table tableparticipantName = new Table();
int rowcount = 1;
int columnCount = numberofparticipants;
for (int i = 0; i < rowcount; i++)
{
TableRow row = new TableRow();
for (int j = 0; j < columnCount; j++)
{
TableCell cell = new TableCell();
TextBox txtNameofParticipant = new TextBox();
txtNameofParticipant.ID = "txtNameofParticipant" + Convert.ToString(i);
cell.ID = "cell" + Convert.ToString(i);
cell.Controls.Add(txtNameofParticipant);
row.Cells.Add(cell);
}
tableparticipantName.Rows.Add(row);
p1.Controls.Add(tableparticipantName);
}
Cache["TempPanel"] = p1;
panelNameofParticipants.Controls.Add(p1);
}
catch(Exception ex)
{
}
}
Look for the p1 panel in the above code to see the changes. Now the code for the CreateControls function need to be changed as following:
public void CreateControls()
{
try
{
Panel p1= (Panel)Cache["TempPanel"];
panelNameofParticipants.Controls.Add(p1);
//String test1 = test.Value;
List<string> listParticipantName = new List<string>();
if (ViewState["numberofparticipants"] != null)
{
int numberofparticipants = Convert.ToInt32(ViewState["numberofparticipants"]);
for (int i = 0; i < numberofparticipants; i++)
{
string findcontrol = "txtNameofParticipant" + i;
TextBox txtParticipantName = (TextBox)panelNameofParticipants.FindControl(findcontrol);
listParticipantName.Add(txtParticipantName.Text);
}
}
}
catch (Exception ex)
{
}
}
Hope this helps.
Dynamically created controls would disappear when page posts back, This article here explains why it happens.
So in order to make dynamic controls be recognized by asp.net page, you need to recreate it in preinit event handler, but I think it is difficult as this dynamic controls in your case rely on some other web form element such as a dropdownlist drpNoofparticipants and also ViewState is not available at this stage.
My suggestion is that we do it in a different way, each post back is actually a form post, so instead of finding the dynamic text box, you could directly get the value via Request.Form collection. Here is the code snippet:
var list = Request.Form.AllKeys.Where(x => x.Contains("txtNameofParticipant"));
foreach (var item in list)
{
var value = Request.Form[item];
}
In this way, you could get the value and since you don't need to rely on ASP.NET engine to retrieve the value from dynamically created control, you could postpone the recreating the table in page_load event handler.
Hope it helps.
Put your btnSubmitCountParticipant_Click method data into other function with name of your choice. Call that function in method btnSubmitCountParticipant_Click and in method CreateControls(). Also cut paste the below code in btnSubmitCountParticipant_Click method
int numberofparticipants =
Convert.ToInt32(drpNoofparticipants.SelectedValue);
ViewState["numberofparticipants"] = numberofparticipants;
. This is working in my machine. Hope this helps
Yes,Dynamic controls are lost in postback,So we need save dynamic control values in Viewsate and again generate dynamic control.I added code here, this working fine
//Create Button Dynamic Control
protected void btnDyCreateControl_Click(object sender, EventArgs e)
{
try
{
int numberofparticipants = 5;
ViewState["numberofparticipants"] = numberofparticipants;
int test = (int)ViewState["numberofparticipants"];
int rowcount = 1;
int columnCount = numberofparticipants;
CreateDynamicTable(rowcount, columnCount);
}
catch (Exception ex)
{
}
}
//submit values
protected void btnSave_Click(object sender, EventArgs e)
{
try
{
List<string> listParticipantName = new List<string>();
if (ViewState["numberofparticipants"] != null)
{
int numberofparticipants = Convert.ToInt32(ViewState["numberofparticipants"]);
foreach (Control c in panelNameofParticipants.Controls)
{
if (c is Table)
{
foreach (TableRow row in c.Controls)
{
int i = 0;
foreach (TableCell cell in row.Controls)
{
if (cell.Controls[0] is TextBox)
{
string findcontrol = "txtNameofParticipant" + i;
TextBox txtParticipantName = (TextBox)cell.Controls[0].FindControl(findcontrol);
listParticipantName.Add(txtParticipantName.Text);
}
i++;
}
}
}
}
}
}
catch (Exception ex)
{
}
}
//Save ViewState
protected override object SaveViewState()
{
object[] newViewState = new object[3];
List<string> txtValues = new List<string>();
foreach (Control c in panelNameofParticipants.Controls)
{
if (c is Table)
{
foreach (TableRow row in c.Controls)
{
foreach (TableCell cell in row.Controls)
{
if (cell.Controls[0] is TextBox)
{
txtValues.Add(((TextBox)cell.Controls[0]).Text);
}
}
}
}
}
newViewState[0] = txtValues.ToArray();
newViewState[1] = base.SaveViewState();
if (ViewState["numberofparticipants"] != null)
newViewState[2] = (int)ViewState["numberofparticipants"];
else
newViewState[2] = 0;
return newViewState;
}
//Load ViewState
protected override void LoadViewState(object savedState)
{
//if we can identify the custom view state as defined in the override for SaveViewState
if (savedState is object[] && ((object[])savedState).Length == 3 && ((object[])savedState)[0] is string[])
{
object[] newViewState = (object[])savedState;
string[] txtValues = (string[])(newViewState[0]);
if (txtValues.Length > 0)
{
//re-load tables
CreateDynamicTable(1, Convert.ToInt32(newViewState[2]));
int i = 0;
foreach (Control c in panelNameofParticipants.Controls)
{
if (c is Table)
{
foreach (TableRow row in c.Controls)
{
foreach (TableCell cell in row.Controls)
{
if (cell.Controls[0] is TextBox && i < txtValues.Length)
{
((TextBox)cell.Controls[0]).Text = txtValues[i++].ToString();
}
}
}
}
}
}
//load the ViewState normally
base.LoadViewState(newViewState[1]);
}
else
{
base.LoadViewState(savedState);
}
}
//Create Dynamic Control
public void CreateDynamicTable(int rowcount, int columnCount)
{
Table tableparticipantName = new Table();
for (int i = 0; i < rowcount; i++)
{
TableRow row = new TableRow();
for (int j = 0; j < columnCount; j++)
{
TableCell cell = new TableCell();
TextBox txtNameofParticipant = new TextBox();
txtNameofParticipant.ID = "txtNameofParticipant" + Convert.ToString(j);
cell.ID = "cell" + Convert.ToString(j);
cell.Controls.Add(txtNameofParticipant);
row.Cells.Add(cell);
}
tableparticipantName.Rows.Add(row);
tableparticipantName.EnableViewState = true;
ViewState["tableparticipantName"] = true;
}
panelNameofParticipants.Controls.Add(tableparticipantName);
}
Reference Link,MSDN Link, Hope it helps.
When creating your textboxes make sure you set the ClientIDMode
I recently worked on something similar. I dynamically created checkboxes in GridView rows and it worked for me.
TextBox txtNameofParticipant = new TextBox();
txtNameofParticipant.ID = "txtNameofParticipant" + Convert.ToString(i);
txtNameOfParticipant.ClientIDMode = System.Web.UI.ClientIDMode.Static;
Dynamically added controls have to be created again on postback, otherwise the state of the dynamically added controls will get lost (if the controls lost how can one preserve their old state) . Now the question. When is the viewstated loaded? It is loaded in between the two events Page_Init and Load.
Following code samples are a bit modification of your code for your understanding
The aspx markup is same as yours, but with some extra controls
<form id="form1" runat="server">
<asp:DropDownList ID="drpNoofparticipants" runat="server" >
<asp:ListItem>1</asp:ListItem>
<asp:ListItem>2</asp:ListItem>
<asp:ListItem>3</asp:ListItem>
<asp:ListItem>4</asp:ListItem>
<asp:ListItem>5</asp:ListItem>
<asp:ListItem>6</asp:ListItem>
<asp:ListItem>7</asp:ListItem>
<asp:ListItem>8</asp:ListItem>
<asp:ListItem>9</asp:ListItem>
<asp:ListItem>10</asp:ListItem>
</asp:DropDownList>
<br /><asp:Button ID="btnCreateTextBoxes" runat="server" OnClick="btnSubmitCountParticipant_Click" Text="Create TextBoxes" />
<div id="divNameofParticipants" runat="server">
<asp:Panel ID="panelNameofParticipants" runat="server">
</asp:Panel>
</div>
<div>
<asp:Button ID="btnSubmitParticipants" runat="server" Text="Submit the Participants" OnClick="BtnSubmitParticipantsClicked" />
</div>
</form>
On click event of the btnCreateTextBoxes button i am creating the controls using the following code
private void CreateTheControlsAgain(int numberofparticipants)
{
try
{
ViewState["numberofparticipants"] = Convert.ToString(numberofparticipants);
Table tableparticipantName = new Table();
int rowcount = 1;
int columnCount = numberofparticipants;
for (int i = 0; i < rowcount; i++)
{
for (int j = 0; j < columnCount; j++)
{
TableRow row = new TableRow();
TableCell cell = new TableCell();
TextBox txtNameofParticipant = new TextBox();
txtNameofParticipant.ID = "txtNameofParticipant" + Convert.ToString(j);
cell.ID = "cell" + Convert.ToString(j);
cell.Controls.Add(txtNameofParticipant);
row.Cells.Add(cell);
tableparticipantName.Rows.Add(row);
}
}
panelNameofParticipants.Controls.Add(tableparticipantName);
}
catch (Exception ex)
{
}
}
As mentioned above to maintain the control state, i included the re-creation of the controls in the page Load event based on the viewstate["numberofparticipants"]
protected void Page_Load(object sender, EventArgs e)
{
if (ViewState["numberofparticipants"] != null)
{
CreateTheControlsAgain(Convert.ToInt32(ViewState["numberofparticipants"]));
CreateControls();
}
}
On click event of btnSubmitParticipants button i wrote the following event and writing the participants names to the console
try
{
//String test1 = test.Value;
List<string> listParticipantName = new List<string>();
if (ViewState["numberofparticipants"] != null)
{
int numberofparticipants = Convert.ToInt32(ViewState["numberofparticipants"]);
for (int i = 0; i < numberofparticipants; i++)
{
string findcontrol = "txtNameofParticipant" + i;
var txtParticipantName = panelNameofParticipants.FindControl(string.Format("txtNameofParticipant{0}", i)) as TextBox;
listParticipantName.Add(txtParticipantName.Text);
}
}
foreach (var item in listParticipantName)
{
Response.Write(string.Format("{0}<br/>", item));
}
}
catch (Exception ex)
{
}
Hope this helps
I'm not sure if this is desired, but you're adding multiple tables to your panel, but I think you only want/need one table. So this line should be outside the outer for loop like so:
for (int i = 0; i < rowcount; i++)
{
TableRow row = new TableRow();
for (int j = 0; j < columnCount; j++)
{
TableCell cell = new TableCell();
TextBox txtNameofParticipant = new TextBox();
txtNameofParticipant.ID = "txtNameofParticipant" + Convert.ToString(i);
cell.ID = "cell" + Convert.ToString(i);
cell.Controls.Add(txtNameofParticipant);
row.Cells.Add(cell);
}
tableparticipantName.Rows.Add(row);
}
panelNameofParticipants.Controls.Add(tableparticipantName);
Additionally, FindControl will only search the direct children of the container, in this case it can only find the table, else it'll return null. so you need to search children of the panel to find the control, e.g. your table:
foreach (TableRow row in tableparticipantName.Rows)
{
TextBox txtParticipantName = (TextBox)row.FindControl(findcontrol);
listParticipantName.Add(txtParticipantName.Text);
}
If that doesn't work then doing it recursively might work better:
ASP.NET Is there a better way to find controls that are within other controls?

ASP.NET loop through datatable column and write a checkbox for each item

I'm brand new to ASP.NET with intermediate C# level, and previously I wrote a PHP project. I'm now stuck trying to get a similar effect in ASP.NET.
What I'm using:
The project is C# ASP.NET Empty web application. I'm using Visual Studio 2010 with SP1.
MSSQL 2008 R2
What I want to do is add HTML code using a foreach into the ASP file, specific content area.
This is what I would do in php:
foreach ($library as $book)
{
print "<a href=\"bookpage.php?id=".$book[book_id]"";
print "<h3>".$book[book_author]."</h3>";
print " <p>".$book[book_blurb]."</p>";
}
This is what I've tried in ASP:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server">
<asp:RadioButtonList ID="RadioButtonPizzaList" runat="server">
<asp:ListItem Text="Margerita" />
<asp:ListItem Text="Hawaain" />
<asp:ListItem Text="Meat Supreme" />
</asp:RadioButtonList>
</asp:Content>
But instead of hardcoding, I want to add a listitem for each pizza thats been retrieved from the database, the names of pizza are stored in an array. How would I use a loop and add an HTML line like what I did in above PHP example?
I assume that your pizza list has two columns that Id and PizzaName.
And you have a method that getting pizza list from db as named GetList in Pizza class.
Firstly you should add two attributes in aspx side to your radio button list control.
They are DataValueField and DataTextField.
These attributes required for data binding.
Aspx Side
<asp:RadioButtonList ID="RadioButtonPizzaList" DataValueField="Id" DataTextField="PizzaName" runat="server">
</asp:RadioButtonList>
Code behind Side
private void FillPizzaList()
{
DataTable dtList = Pizza.GetList();
this.RadioButtonPizzaList.DataSource = dtList;
this.RadioButtonPizzaList.DataBind();
}
If you want to get selected item value you can get with this code
this.RadioButtonPizzaList.SelectedValue
Note: If you fill radiobutton list in page load event, do not forget check is postback.
if ( !IsPostBack )
this.FillPizzaList();
In the end, the answer to my problem was using c# to create the table and add rows, and in the cells add the content. One of the questions around here while I was looking around was kind of answered, but not fully. So if you see this you can adapt it.
I've changed from using checkboxes to simply adding text to the cell area, but to answer my original question, one can do what I did with the textboxes and choose which cells to add the checkboxes, or simply do without the table and loop checkboxes into your wanted area.
At the end I add the table to a div that is ready made in the asp code
public partial class _Default : System.Web.UI.Page
{
Database doDatabase = new Database();//custom class for querying a database
ArrayList textboxNames = new ArrayList();//just to make life easier
ArrayList pizzaNames = new ArrayList();//just to make life easier
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
}
this.FillPizzaList();
}
private void FillPizzaList()
{
int count = 1;
string query = "select FoodID, FoodName, 'R' + Convert(char(10), FoodPrice)[Food Price], rtrim(FoodDesc)[FoodDesc] from tblFood";
doDatabase.Do_SQLQuery(query);
Table tablePizza = new Table();
TableRow tr = new TableRow();
TableCell tc = new TableCell();
for (int c = 0; c < 4; c++)
{
tc = new TableCell();
if (c == 0)
{
tc.Width = new Unit("15%");
tc.Text = "<h3>Pizza Name</h3>";
}
else if (c == 1)
{
tc.Text = "<h3>Pizza Description</h3>";
}
else if (c == 2)
{
tc.HorizontalAlign = HorizontalAlign.Center;
tc.Width = new Unit("15%");
tc.Text = "<h3>Pizza Price</h3>";
}
else if (c == 3)
{
tc.Width = new Unit("12%");
tc.Text = "<h3>Pizza Quantity</h3>";
}
tr.Cells.Add(tc);
}
tablePizza.Rows.Add(tr);
foreach (DataRow dr in doDatabase.dataTbl.Rows)
{
tr = new TableRow();
for (int c = 0; c < 4; c++)
{
tc = new TableCell();
if (c == 0)
{
pizzaNames.Add(dr["FoodName"].ToString());
tc.Text = dr["FoodName"].ToString();
}
else if (c == 1)
{
tc.Text = dr["FoodDesc"].ToString();
}
else if (c == 2)
{
tc.HorizontalAlign = HorizontalAlign.Center;
tc.Text = dr["Food Price"].ToString();
}
else if (c == 3)
{
TextBox MyTextBox = new TextBox();
MyTextBox.ID = "Quantity" + count;
textboxNames.Add("Quantity" + count);
MyTextBox.Text = "0";
tc.Controls.Add(MyTextBox);
count++;
}
tr.Cells.Add(tc);
}
tablePizza.Rows.Add(tr);
}
pizzaMenu.Controls.Add(tablePizza);//add table to div
}

ASP.NET dynamically-generated TableRows won't persist between postbacks

In the ASPX
<asp:Table ID="superTable" runat="server" Width="100%">
<%--populate me on the fly!--%>
</asp:Table>
<asp:Button ID="btnAddRow" runat="server" CausesValidation="false" Text="Add Row" onclick="btnAddRow_Click" Width="90%"/>
<asp:Button ID="btnRemoveRow" runat="server" CausesValidation="false" Text="Remove Last Row" onclick="btnRemoveRow_Click" Width="90%"/>
<asp:Button ID="btnSubmit" runat="server" Text="1" onclick="btnSubmit_Click" Width="90%"/>
Relevant bits of CodeBehind
protected void Page_Load(object sender, EventArgs e)
{if (!IsPostBack){ writeHeader(); makeMeARow(); }}
protected void btnAddRow_Click(object sender, EventArgs e)
{
if (int.Parse(btnSubmit.Text) <= 20)
{ int b = superTable.Rows.Count+1;
writeHeader();
btnSubmit.Text = (int.Parse(btnSubmit.Text) + 1).ToString();
for (int a = 1; a <= int.Parse(btnSubmit.Text); a++)
{ makeMeARow(); }
}
else{/*tell user they can't do that! Max of 20 rows as noted by form requirements */}
}
private void writeHeader()
{
//= == create row == =//
TableHeaderRow tempHeaderRow = new TableHeaderRow();//make row
//= == create cells == =//
TableHeaderCell tempHeaderCell01 = new TableHeaderCell();
TableHeaderCell tempHeaderCell02 = new TableHeaderCell();
TableHeaderCell tempHeaderCell03 = new TableHeaderCell();
tempHeaderCell01.Text = "Call Number"; tempHeaderCell01.Width = Unit.Percentage(33);
tempHeaderCell02.Text = "Author"; tempHeaderCell02.Width = Unit.Percentage(33);
tempHeaderCell03.Text = "Title"; tempHeaderCell03.Width = Unit.Percentage(33);
//= == add TableCells to TableRow == =//
tempHeaderRow.Cells.Add(tempHeaderCell01);
tempHeaderRow.Cells.Add(tempHeaderCell02);
tempHeaderRow.Cells.Add(tempHeaderCell03);
//superTable.Rows.AddAt(superTable.Rows.Count, tempRow);
superTable.Rows.Add(tempHeaderRow);
}
protected void btnRemoveRow_Click(object sender, EventArgs e)
{ int b = superTable.Rows.Count - 1;
writeHeader();
btnSubmit.Text = (int.Parse(btnSubmit.Text) - 1).ToString();
for (int a = 1; a <= int.Parse(btnSubmit.Text); a++)
{makeMeARow();}
}
private void makeMeARow()
{
//= == maybe off by one? == =//
string rowCount = superTable.Rows.Count.ToString("00");
//= == create row == =//
TableRow tempRow = new TableRow();//make row
//= == create cells == =//
TableCell tempCell01 = new TableCell();
TableCell tempCell02 = new TableCell();
TableCell tempCell03 = new TableCell();
//= == create TextBoxes == =//
TextBox tempTextBox01 = new TextBox();
TextBox tempTextBox02 = new TextBox();
TextBox tempTextBox03 = new TextBox();
//= == change the ID of TableRow == =//
tempRow.ID = "tableRow_" + rowCount;
//= == change the IDs of TableCells == =//
tempCell01.ID = "tableCell_" + rowCount + "_01";
tempCell02.ID = "tableCell_" + rowCount + "_02";
tempCell03.ID = "tableCell_" + rowCount + "_03";
//= == change the IDs of TextBoxes == =//
tempTextBox01.ID = "txtCallNumber_" + rowCount;
tempTextBox02.ID = "txtAuthor_" + rowCount;
tempTextBox03.ID = "txtTitle_" + rowCount;
//= == change TextBox widths to 90%;
tempTextBox01.Width = Unit.Percentage(90);
tempTextBox02.Width = Unit.Percentage(90);
tempTextBox03.Width = Unit.Percentage(90);
//= == add TextBoxes to TableCells == =//
tempCell01.Controls.Add(tempTextBox01);
tempCell02.Controls.Add(tempTextBox02);
tempCell03.Controls.Add(tempTextBox03);
//= == add TableCells to TableRow == =//
tempRow.Cells.Add(tempCell01);
tempRow.Cells.Add(tempCell02);
tempRow.Cells.Add(tempCell03);
//add TableRow to superTable
//superTable.Rows.AddAt(superTable.Rows.Count, tempRow);
superTable.Rows.Add(tempRow);
}
Okay, so, my problem;
-when I hit either the "Add Row" or "Remove Row" button, the data in the cells don't persist between postbacks. The relevant rows and cells hold the same IDs, but don't persist data. Why not?
Dynamic controls must be re-added to the form on each postback. Typically this is done during the Init phase of the page's lifecycle. The controls that you have added dynamically DO actually have ViewState. When the appropriate control is re-added to the control tree using the exact same ID it had before, it should reappear with the values that were persisted in ViewState.
Check out this article for simple tips on using dynamic controls or you can check out this tutorial from 4 Guys from Rolla for a more in-depth look.

Table generation from Code Behind

I know what my fault is, but not sure how to resolve. I am trying to generate an asp:table from Code Behind.
The table should be 3 cells wide... I'll work on the row limit later.
Here's my code:
GallaryImage g = new GallaryImage();
var images = g.GetAll();
photos.Style.Add("width","100%");
photos.Style.Add("border-style","none");
TableRow tr = new TableRow();
TableCell tc = new TableCell();
tr.Cells.Add(tc);
tr.Cells.Add(tc);
tr.Cells.Add(tc);
int cntr = 0;
TableRow row = new TableRow();
foreach (var image in images)
{
cntr++;
TableCell cell = new TableCell();
Image i = new Image();
i.ImageUrl = image.fullThumbPath;
cell.Controls.Add(i);
row.Cells.Add(cell);
if(cntr%3==0)
{
photos.Rows.Add(row);
row.Cells.Clear();
}
}
if(row.Cells.Count > 0)
photos.Rows.Add(row);
}
My problem is that I need to create a new row in the Foreach, only when I need the new row... i.e, when we have added 3 cells.
I thought I could add the row to the table, and then clear the row to start a new row - but that's not working, as I just keep clearing the same row object... and therefore, never add multiple rows.
Can someone assist with my logic here?
GallaryImage g = new GallaryImage();
var images = g.GetAll();
photos.Style.Add("width","100%");
photos.Style.Add("border-style","none");
int cntr = 0;
TableRow row = new TableRow();
foreach (var image in images)
{
cntr++;
TableCell cell = new TableCell();
Image i = new Image();
i.ImageUrl = image.fullThumbPath;
cell.Controls.Add(i);
row.Cells.Add(cell);
if(cntr%3==0)
{
photos.Rows.Add(row);
row = new TableRow();
}
}
if(row.Cells.Count > 0)
photos.Rows.Add(row);
}

Create Runtime LinkButton

For creating runtime linkbutton i used this code
for (int i = 0; i <= 10; i++)
{
r = new TableRow();
t.Rows.Add(r);
for (int j = 0; j <= 2; j++)
{
c = new TableCell();
r.Cells.Add(c);
LinkButton btnLnk = new LinkButton();
btnLnk.Text = "Hello";
btnLnk.Visible = true;
btnLnk.CommandName = "Test";
btnLnk.CommandArgument = "1";
btnLnk.ID = "Hi";
c.Controls.Add(ll);
}
}
This Error is occured...
"Control 'ctl34' of type 'LinkButton' must be placed inside a form tag with runat=server. "
Please give me soluation for this
Make sure you table (t) is inside the form tag.
Most likely the Form in which this table is located to which you are adding a LinkButton does not specify the runat=server attribute, or this Table is not in the Form at all.
Make sure you have something like this.
<form runat="server">
<!--table to which you are adding your rows-->
</form>
first give id to your form say <form id="myForm" runat="server">
then in code behind you can add table to the form like this
myForm.Controls.Add(t);

Categories