ASP.NET control lifecycle. Control property changes only available on next load - asp.net

I have built a pager control with various properties, for example Start to indicate the first record which should be rendered. This is embedded in another control which actually renders the list of records. The properties' getters and setters use ViewState to persist and retrieve the values.
The links in the pager are dynamically created during the page_load. On each link, the anchor.ServerClick delegate is wired up to a lambda that sets the Start property on the pager control.
When I debug the page, I can see that the Start property is indeed updated, but that the changed value is only available the next time I load the page, presumably persisted via the ViewState mechanism.
What this means in practice is that the embedding control doesn't see the updated values of these properties in time to render the correct list. How can I have the visitor's click update the pager properties before they get used rather than afterwards?
EDIT: adding some code
Called from the Page_Load of the main control, I have a loop that references the properties of the pager. This loop determines the items which will be displayed, and if the control properties were updated by this point, it would display the correct records, but that's not the case.
for (int i = pager.Start - 1 ;
i < queryResults.Count() && i <= (pager.Start + pager.PageSize); i++) {
In the pager control, also called from the Page_Load, there's code like this, that adds child controls and wires up the delegate.
HtmlAnchor a = new HtmlAnchor();
a.HRef = "#";
a.InnerText = page.ToString();
newStartNumber = ((page - 1) * this.PageSize) + 1;
a.Attributes["data-start"] = newStartNumber.ToString();
a.ServerClick += (sender, e) =>
{ this.Start = int.Parse(((HtmlAnchor)sender).Attributes["data-start"]); };
li.Controls.Add(a);
ul.Controls.Add(li);
So when these anchors are clicked, the pager's Start property is updated, but it's too late.

As far as I know, these code parts seem ok, provided :
Your Page property looks like this :
public int Page
{
get { return ViewState["Page"] == null ? 0: (int)ViewState["Page"]; }
set { ViewState["Page"] = value; }
}
and this :
for (int i = pager.Start - 1 ;
i < queryResults.Count() && i <= (pager.Start + pager.PageSize); i++) {
is in the preRender of your parent control.
And this :
HtmlAnchor a = new HtmlAnchor();
a.HRef = "#";
a.InnerText = page.ToString();
newStartNumber = ((page - 1) * this.PageSize) + 1;
a.ServerClick += (sender, e) => { this.Start = newStartNumber; };
li.Controls.Add(a);
ul.Controls.Add(li);
is in the pageload (or init) of your pager control. (maybe you don't need the data-start attribute)
You should give Ids to your HtmlAnchors.

Related

Change GridView Cells colour if the cells have the Random number generated every 3 seconds in asp.net

I have a multiple GridView generate dynamically placed inside an update panel where its data source is from the database.
What i want to do is change the color of the Gridview cells that contains all the 90 random number generated every three seconds. The part where i am having problem is that the page waits untill all the random numbers are generated and displays the final output instead of updating the Gridview cells color every time the random number is being generated.I know the problem is with the page lifecycle thing but, i dont know how to approach this problem. Can someone please guide me?
namespace validation
{
public partial class index : System.Web.UI.Page
{
int countTik;
protected void Page_Load(object sender, EventArgs e)
{
//Calling javascript
// ScriptManager.RegisterClientScriptBlock(this,GetType(), "mykey", "myFunction();", true);
// GridView gridview = new GridView();
//HiddenField1.Value = "2";
DataAccessForUserInterface ds = new DataAccessForUserInterface();
countTik = ds.selectAll();
for (int k = 1; k <= countTik; k++)
{
UpdatePanel updatePanel = new UpdatePanel();
updatePanel.ID = "panel"+k;
string Ticketname = "TicketNo" + k;
GridView gridview = new GridView();
RetriveTickets RetTik = new RetriveTickets();
List<RetriveTickets> Ticketdata = ds.GetMasterDetails(Ticketname).ToList();
RetTik.row1 = Ticketdata[0].row1;
RetTik.row2 = Ticketdata[0].row2;
RetTik.row3 = Ticketdata[0].row3;
DataTable dataTable1 = new DataTable();
dataTable1.Columns.Add("1");
dataTable1.Columns.Add("2");
dataTable1.Columns.Add("3");
dataTable1.Columns.Add("4");
dataTable1.Columns.Add("5");
dataTable1.Columns.Add("6");
dataTable1.Columns.Add("7");
dataTable1.Columns.Add("8");
dataTable1.Columns.Add("9");
//rows
// List<int> first = new List<int>();
foreach (var item in Ticketdata[0].row1)
{
var row = dataTable1.NewRow();
row["1"] = item.C0;
row["2"] = item.C1;
row["3"] = item.C2;
row["4"] = item.C3;
row["5"] = item.C4;
row["6"] = item.C5;
row["7"] = item.C6;
row["8"] = item.C7;
row["9"] = item.C8;
dataTable1.Rows.Add(row);
}
DataTable dataTable2 = new DataTable();
dataTable2.Columns.Add("1");
dataTable2.Columns.Add("2");
dataTable2.Columns.Add("3");
dataTable2.Columns.Add("4");
dataTable2.Columns.Add("5");
dataTable2.Columns.Add("6");
dataTable2.Columns.Add("7");
dataTable2.Columns.Add("8");
dataTable2.Columns.Add("9");
//rows
foreach (var item in Ticketdata[0].row2)
{
var row = dataTable2.NewRow();
row["1"] = item.C0;
row["2"] = item.C1;
row["3"] = item.C2;
row["4"] = item.C3;
row["5"] = item.C4;
row["6"] = item.C5;
row["7"] = item.C6;
row["8"] = item.C7;
row["9"] = item.C8;
dataTable2.Rows.Add(row);
}
DataTable dataTable3 = new DataTable();
dataTable3.Columns.Add("1");
dataTable3.Columns.Add("2");
dataTable3.Columns.Add("3");
dataTable3.Columns.Add("4");
dataTable3.Columns.Add("5");
dataTable3.Columns.Add("6");
dataTable3.Columns.Add("7");
dataTable3.Columns.Add("8");
dataTable3.Columns.Add("9");
//rows
foreach (var item in Ticketdata[0].row3)
{
var row = dataTable3.NewRow();
row["1"] = item.C0;
row["2"] = item.C1;
row["3"] = item.C2;
row["4"] = item.C3;
row["5"] = item.C4;
row["6"] = item.C5;
row["7"] = item.C6;
row["8"] = item.C7;
row["9"] = item.C8;
dataTable3.Rows.Add(row);
}
dataTable2.Merge(dataTable3);
dataTable1.Merge(dataTable2);
gridview.ID = "gridview" + k;
gridview.CssClass = "table table-bordered table-dark";
//gridview.AutoGenerateColumns = true;
//gridview.HeaderStyle.CssClass = "table-primary";
gridview.ShowHeader = false;
gridview.DataSource = dataTable1;
// gridview.DataBound += new EventHandler(groupHeader);
gridview.RowDataBound += new GridViewRowEventHandler(Gv_RowDataBound);
gridview.DataBind();
GridViewRow rows = new GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Normal);
TableHeaderCell cell = new TableHeaderCell();
cell.Text = "Customer Name";
cell.ColumnSpan = 5;
rows.Controls.Add(cell);
cell = new TableHeaderCell();
cell.ColumnSpan = 4;
cell.Text = "Ticket Number";
rows.Controls.Add(cell);
// row.BackColor = Color.BlanchedAlmond;
gridview.HeaderRow.Parent.Controls.AddAt(0, rows);
updatePanel.ContentTemplateContainer.Controls.Add(gridview);
grid1.Controls.Add(updatePanel);
}
StartCounting();
}
//fill color of already generated random number stored in database and that exist on the gridview on page load
private void Gv_RowDataBound(object sender, GridViewRowEventArgs e)
{
DataAccessForUserInterface da = new DataAccessForUserInterface();
int[] randomList = da.getRandom();
if (e.Row.RowType == DataControlRowType.DataRow)
{
for (int r = 0; r < 90; r++)
{
for (int i = 0; i <= 8; i++)
{
int num = Convert.ToInt32(e.Row.Cells[i].Text);
if (num != 0 && num == randomList[r])
{
//e.Row.BackColor = Color.Red;
e.Row.Cells[i].BackColor = Color.Green;
}
}
}
}
}
public int[] StartCounting()
{
int[] random = new int[90];
{
int[] randomNumber = new int[90];
int count = 0;
for (int i = 0; i < randomNumber.Length; i++)
{
Random rnd = new Random();
int num = rnd.Next(1, 91);
if (randomNumber.Contains(num))
{
i--;
}
else
{
randomNumber[i] = num;
int countingNumber = randomNumber[i];
count++;
DataAccessForUserInterface da = new DataAccessForUserInterface();
da.insertRandom(countingNumber); // Store Random number generated on Database
Task.Delay(3 * 1000).Wait();
for(int GridCount=1;GridCount<=countTik;GridCount++)
{
GridView gv = (GridView)FindControl("gridview"+GridCount);
foreach (GridViewRow row in gv.Rows)
{
for (int cellIndex = 0; cellIndex < 9; cellIndex++)
{
if (row.Cells[cellIndex].Text.Equals(countingNumber))
{
row.BackColor = Color.Green;
}
}
}
}
}
}
return randomNumber;
}
}
}
}
Well, when you post-back, even in a update panel, the web page travels up to the server. The code behind runs - all of it. WHILE that code runs, the web page is up on the server. ANY change of a control is NOT seen by the user (they have a copy of the web page just sitting on their desktop).
The user ONLY will see ANY updates from your code behind ONLY AFTER the code is 100% done, finished and exits. When the code exists, then the WHOLE page (or update panel ) now travels back down to the client side, and is updated.
So, clearly, any code behind updates - ALL OF them will appear to occur in "one shot" or "one update".
A basic grasp of how web pages work is required here.
You have this:
NOTE SUPER careful in the above - note how NO WEB page is active on the web server side.
You do NOT have this setup:
And you do NOT have this setup:
so, you JUST have a web page sitting on the client side.
If the user clicks a button, or even a button in a update panel, then that post-back starts, you have this:
The page is sent to the web server (it is just sitting there - waiting for ANY user to post back a page - NOT JUST YOUR page!!!!
So, page travels up to web server.
You now have this:
Now, to be fair, in above a copy of the web page is ALSO still sitting on the users desktop - but they see the little spinner - page is waiting for ALL OF AND 100% of the code behind to finish.
You in fact NEVER directly interact with the user with code behind.
Your server side code ONLY interacts with the web page - and for the SHORT time the page is up on the server.
While the code behind runs, you are updating the copy of the browswer on the server side - any chances cannot be seen by the user. In fact, in most cases the order in which you update things don't matter, since ALL of the changes will have to complete.
Once and ONLY once your code behind is done running, then the whole page (or the udpate panel) now travels back to the client side browser, page loads, JavaScript starts to run, and NOW you see the updates from your code behind.
So, they will ALWAYS appear to update in one shot - not control by control.
And EVEN if you put delays in your code - all you will accomplish is to delay the page sitting up on the server for a LONGER period of time - but no updates will be seen client side.
So, after the updates occur (all code behind is done running), then, and only then does the page travel back to the client side, like this:
At that point, the server TOSSES out your web page, destryos the page class, and even all your code varaibles now go out of scope. Very much like when you exit a subroutine call - the local vars and values of that sub (or now the web page) go out of scope.
The web server is now just sitting waiting for ANY user to post back a page (or partial post back via a udpate panel - but the process is the same either way).
So, as a result, you can't put in code delays.
Your have to let the code behind finish.
So, if you want the user to "see" the page update (the squares in your case), then you have to use one of serveral appraoches:
One way:
You put in a JavaScript timer, and have it click a update button (even a hidden one) in the update paneal. Each time you click (say every half second), then you update one square in code behind, and then the update panel will show those results).
Another way is to have a JavaScript timer, it calls a JavaScript routin every second (or maybe half secord, or whatever).
That js routine will thus call a server side web method, get the value back of ONE control or text box, and the update it. This is typically referred to a ajax call.
This can be a complex bit of code. Worse yet, your squares to update are nested in a gridview, making the js code even more diffiuclt.
The most easy way?
Setup a code behind routine, use a session() counter (or view state).
Drop in a timer control into the update panel.
Have the timer control call your update to the grid routine, have it call it say once ever second. When the timer routine triggers, you update 1 box, increment the counter (to update the next box), and code behind exits.
So, you have to setup a routine that can modify ONLY ONE of the text boxes, and exit. You also need some counter that increments.
So for each timer trigger, your timer code calls the udpate routine - updates one text box, increment counter, and is done.
When the timer code figures out you JUST updated the last box, then the timer event can turn off the timer trigger, and the refreshing of the page will stop.
A REALLY simple example would be to have a text box count from 1 to 10, and update each time.
If we just run a for/next loop, put 1 to 10 in the text box, when the user clicks the button, the code can run, shove 1, then 2 etc into the text box. but due to the post-back and round trip diagrams above, the user will ONLY ever see "10" as the final result.
So, lets do the 1 to 10, use a update panel, and a simple text box.
So, we have this markup:
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<br />
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:TextBox ID="txtCount" runat="server"
Height="42px"
Width="42px"
Font-Size="XX-Large"
Text="0"
style="text-align: center">
</asp:TextBox>
<br />
<asp:Button ID="Button1" runat="server" Text="Start Timer" CssClass="btn" OnClick="Button1_Click"/>
<asp:Timer ID="Timer1" runat="server"
Enabled="False"
Interval="1000" OnTick="Timer1_Tick"></asp:Timer>
</ContentTemplate>
</asp:UpdatePanel>
And our code behind can be this:
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
Session["MyCount"] = 0;
Timer1.Interval = 1000; // tick our timer each second
Timer1.Enabled = true;
}
protected void Timer1_Tick(object sender, EventArgs e)
{
int? MyCount = Session["MyCount"] as int?;
if (MyCount < 10 )
{
MyCount = MyCount + 1;
txtCount.Text = MyCount.ToString();
Session["MyCount"] = MyCount;
}
else
{
// we are done, stop the timer
Timer1.Enabled = false;
}
}
And we now see/have this:
So, I suggest you try this on a test page. Drop in that text box, the timer, and the update panel.
Note that if you JUST runt he loop one to 10 in code behind (without the timer), then the code does run, does udpate the text box (1 to 10), but you NEVER see the results, since you just have to refer to the above post-back diagrams to grasp how this works.
So, you need to "run" that code you have to create the new values, but you need a timer, a counter of some time, and each time you increment the timer, you update ONE box in the grid, and then each time the timer fires, you then have to update another box.
When the counter has updated all of teh new changes, then your code behind can set the timer enabled = false to stop this updating process.

Kentico CmsRepeater: When to call databind when DataBindByDefault="false"

I want to set DataBindByDefault to false on my repeater because otherwise it makes a call to the db which returns all data from the child nodes of the page which comes to 12MB.
I've hacked it for now and set the Path value to "." (same page only) in the code in front but it's still an extra db call.
So my plan was to set DataBindByDefault to false, assign the data from my custom query to the repeater and then call databind() as follows:
<cms:CMSRepeater ID="repItems" runat="server" Path="."/>
private void InitRepeater()
{
var data = (DataSet)NewsProvider.GetNews(ClassNames, Path, MaxRelativeLevel, OrderBy, WhereStatement, SelectTopN, -1, -1);
if (!DataHelper.DataSourceIsEmpty(data))
{
repItems.DataSource = data;
repItems.ControlContext = ControlContext;
repItems.EnablePaging = true;
repItems.PageSize = PageSize;
repItems.PagerControl.CurrentPage = 1;
repItems.PagerControl.PageSize = PageSize;
repItems.PagerControl.Visible = false;
repItems.HideControlForZeroRows = true;
repItems.TransformationName = Transformation;
repItems.DataBind();
}
}
InitRepeater() is called from SetupControl() which called from OnContentLoaded() and ReloadData() but nothing gets rendered.
If I try calling InitRepeater() in PreRender it renders but it ignores the paging settings.
I'm using Kentico v12.0.65
You should be using the LoadPagesIndividually property of the repeater control. If true, each page is loaded individually in case of paging.

Dynamic controls(Textbox) in asp.net

I want to create dynamic text boxes during run time.
Suppose im gettng a text from a database as "# is the capital of India" now i want to replace that "#" by text box while it is rendered to user as below
<asp:TextBox runat="server" id = "someid"></asp:TextBox> is the capital of India
Im able to get the textbox and text as combination. However I cannot access the textboxes with the given id and when any event occurs on the page the textboxes are lost as they logically does not exist untill their state is stored.
I also went through the concepts of place holder and Viewstate to store the dynamically created controls and make their id's available for the methods, but as far as I tried I could not meet the textbox and text combination requirement.
Im looping over the entire text recieved from database and checking if there is any"#". Is yes then i want to replace it with a textbox on which i can call methods to take back the value entered in the text box to database and store it.
eg: text is "#" is the capital of India
for (int i = 0; i < que.Length; j++) //que holds the text
{
if (que[i] == '#')
{
//Textbox should be created
}
else
{
//the texts should be appended before or after the textbox/textboxes as text demands
}
}
On button click I'm passing request to database, which will send me necessary details i.e. question text, options and also saves the current checked value etc.
protected void BtnLast_Click(object sender, EventArgs e)
{
CheckBox1.Checked = false;
CheckBox2.Checked = false;
CheckBox3.Checked = false;
CheckBox4.Checked = false;
QuestionSet q = new QuestionSet();
StudentB b = new StudentB();
q = b.GetQuestion(1, 1, qid, 'L', 0, Checked, date);
qid = Convert.ToInt32(q.Question_Id);
Checked = q.Checked;
if (q.Question_Type == 11) //indicates its objective Question
{
//ill bind data to checkboxes
}
else if (q.Question_Type == 12) // indicate its fill in the blanks question
{
for (int j = 0; j < que.Length; j++)
{
if (que[j] == '#')
{
count++;
string res = "<input type = 'text' runat = 'server' id ='TxtBoxFillUp" + count + "'/>";
htm = htm.Append(res);
}
else
{
htm = htm.Append(que[j]);
}
}
}
}
Any help will be greatly appreciated, thanks in advance.
Adding control in the way you do it won't create control as asp.net creates it. You do have to create controls as usual .net object.
TextBox myNewTextBox = new TextBox() {};
// Set all initial values to it
And add this cotrol to placeholder or panel, whatever you use. Keep in mind that asp.net page events fire even if you use update panel, so in order to maintain state and events of newly created controls you have take care of creating such controls long before page's Load event fires. Here is my answer to another simialiar question.
Seeing the requirements you have:
1.) You need to use JavaScript. Since the ASP.NET will not recreate controls which are dynamically added. Dynamically added controls need to be recreated after every postback. This is the reason why your TextBoxes are Lost after every postback.
2.) You can write JavaScript code to Hide and show the textboxes for blank texts since at every button click you can call Client side functions using: OnClientClick() property of buttons.
3.) Also to Get the TextBoxes using ID property, add them in Markup( .aspx ) portion itself.

Find ListBoxes in ASP .NET

i have created dynamic listboxes (4 to 10) in ASP.NET.
and my question is , How do i find the dynamically created listboxes using c#?
thanks
Sure... and i appreciate your help . below code i am using for creating dynamic LB
protected void btndyfilter_Click(object sender, EventArgs e)
{
int numberOfListBox = lbFilter.GetSelectedIndices().Length;
string lbname = lbFilter.SelectedValue;
for (int i = 0; i < numberOfListBox; i++)
{
ListBox listb = new ListBox();
ListItem lItem = new ListItem();
listb.SelectionMode = System.Web.UI.WebControls.ListSelectionMode.Multiple;
listb.Height = 150;
listb.Width = 200;
lItem.Value = i.ToString();
lItem.Text = lbname;
listb.Items.Add(lItem);
panFilter.Controls.Add(listb);
//once we created the LB dynamically i need to populate each LB with the corresponding values
connstr2 = System.Configuration.ConfigurationManager.ConnectionStrings["connstr"].ConnectionString;
conn2.ConnectionString = connstr2;
conn2.Open();
CubeCollection CubeList = conn2.Cubes;
string cb = ddlCubeList.SelectedItem.Text;
//need to remove the Hardcoded Code
foreach (Member dimem in CubeList[cb].Dimensions["Date"].Hierarchies["Calendar Date"].Levels["Date"].GetMembers())
{
ListItem Memlist = new ListItem();
Memlist.Text = dimem.UniqueName;
lbFilter.Items.Add(Memlist);
}
}
panFilter.Visible = true;
panCubeDef.Visible = true;
}
so this will create the LB i believe :)... and Inside the commented code i need to use to populate for each LB item ..perhaps it bit hardcoded which i need to remove. so i all dynamic LBs are populated then the selected items from all LBs will come into the where clause in my MDX query..hope i did not confuse you
There is 2 way either you can store dynamic control detail with dictionary or just find when you want to use it using some code like this
Control GetControlByName(string Name)
{
foreach(Control c in this.Controls)
if(c.Name == Name)
return c;
return null;
}
while generating ListBox dynamically, give ListBox ID as:
lstBoxNo1, lstBoxNo2. lstBoxNo3 etc. where 1,2,3(no) will be from count.
like
int count=1;
generate listbox control
listboxid=lastBoxNo+count;
count++
`by doing this, u have control over id's.
else use
http://stackoverflow.com/questions/3731007/using-findcontrol-to-find-control
using this link to understand findcontrol.
The points that you wont to find that dynamic controls are.
The moment you first render the page.
On every other post back.
In the case of 1, then you better keep a variable on your page that keep that creations.
In the case of 2, when you have post back, you need to store somehow the creations of your control in the page when you render it. One good place is to keep that information on the viewstate.
You can also on the post back, just to check if you have any post back valued from controls that you have named with a serial numbering starting from 1, eg You start looking if you have post back from ControlName_1, then ControlName_2, and when you not found any other value you end.

Why is my ASP.NET Button control not calling the appointed function?

I want to set up a search functionality on my web site. The user types some information into a text box and click a search button. Upon clicking the search button, a database is searched using the text in the text box, and the results are displayed in a table. If the text in the text box matches one result from the database perfectly, rather than displaying a list of results the page is populated with detailed information about the matching result.
In order to make it easier to match a result exactly, I want to add a button next to each result which "selects" that result, filling the text box with that result's text and therefore populating the page with the details. Here's what I have.
Upon clicking the search button, after the check to see if a result is matched exactly, I create a table which contains the results and the buttons:
for(int x=0; x < res_list.Length; x++)
{
TableRow newRow = new TableRow();
TableCell textCell = new TableCell();
TableCell buttonCell = new TableCell();
buttonCell.ID = "bc" + x;
Button cellButton = new Button();
cellButton.ID = "btn" + x;
textCell.Text = res_list[x];
textCell.Attributes.Add("Width","60%");
cellButton.Text = x.ToString();
// cellButton.OnClientClick = "NameClick"; This property refers to client-side scripts, which I am not using.
cellButton.Click += new EventHandler(NameClick);
buttonCell.Controls.Add(cellButton);
newRow.Cells.Add(firstCell);
newRow.Cells.Add(buttonCell);
myTable.Rows.Add(newRow);
}
I have tried both the OnClientClick method and the Click method seen above, both of which have yielded the same results.
My NameClick function is as follows:
void NameClick(object sender, EventArgs e)
{
Button sendButton = (Button)sender;
int index = Int32.Parse(sendButton.Text);
SearchTextBox.Text = myTable.Rows[index].Cells[0].Text;
return;
}
I set up a breakpoint at the beginning of the NameClick function, and when I click one of these buttons it is never reached. Why is this function not being called by my buttons?
EDIT: I want to accomplish this without using JavaScript, if possible.
You use cellButton.OnClientClick = "NameClick";, but do you actually have a NameClick function in your javascript? If not, clicking the button will cause a JS error which will probably block the postback.
Other than that, it is advisable to assign explicit ID's to controls which you create programatically. Otherwise the autogenerated ID's may change on postback, which will prevent control events from firing.
Something like the following should work (not tested):
myTable.ID = "someid";
for (int x=0; x < res_list.Length; x++)
{
TableRow newRow = new TableRow();
newRow.ID = "r" + x;
TableCell textCell = new TableCell();
TableCell buttonCell = new TableCell();
buttonCell.ID = "bc" + x;
Button cellButton = new Button();
cellButton.ID = "btn" + x;
textCell.Text = res_list[x];
textCell.Attributes.Add("Width","60%");
cellButton.Text = x.ToString();
//cellButton.OnClientClick = "NameClick"; // not needed unless you have actual JS for it
cellButton.Click += new EventHandler(NameClick);
buttonCell.Controls.Add(cellButton);
newRow.Cells.Add(firstCell);
newRow.Cells.Add(buttonCell);
myTable.Rows.Add(newRow);
}
cellButton.OnClientClick should point to a client-side function, i.e. JavaScript. Do you have a JS function somewhere?
If the answer is no, then we've found your problem. You should create one. It will be helpful to set your ClientIDMode property of your dynamically generated controls to Static or Predictable, so your JS function can easiliy access them.
Do you need assistance with the JS function?
when you click on the button, the page start the life cycle again and your control Does not exist in the page you need to create the control again or save it in the viewstate or use control state
when he call back in the life cycle
in the page life cycle event SaveControlState, loadControlState
if you want to create a javascript click event you need to make sure that the control doesnt call to server side event for this in the javascript function you need to return false
you have to add this event in your asp syntax for button.
<asp:Button runat="server " OnClick="ButtonClick"/>

Resources