Dynamically generated controls not being found via FindControl - c#

I have a asp:panel that on a button click, I add some number of checkboxes to dynamically.
On another button click, I need to look at these checkboxes and check if they are checked.
I can't find the controls. I've tried doing FindControl with the ID that I've supplied it, as well as the ClientID.
The markup with the panel that the checkboxes get placed into, and the two buttons:
<asp:Panel runat="server" ScrollBars="Vertical" ID="pnlEmailCheckboxes" Height="150">
<br/>
<asp:CheckBox runat="server" Text="Other" ID="cbOtherEmail"/>
<asp:TextBox ID="txtOtherEmail" runat="server" Style="width: 270px;" CssClass="textbox-default"></asp:TextBox>
<br/>
</asp:Panel>
<asp:LinkButton ID="btnSendEmail" Text="<span>Send Email</span>" runat="server" CssClass="page-footer-button-highlight" OnClick="btnSendEmail_Click"></asp:LinkButton>
<asp:LinkButton ID="btnCloseEmail" Text="<span>Close</span>" runat="server" CssClass="page-footer-button" CausesValidation="false" OnClick="btnCloseEmail_OnClick"></asp:LinkButton>
The event that generates the textboxes:
protected void btnEmail_Click(object sender, EventArgs e)
{
List<CheckBox> cbList = new List<CheckBox>();
for (int i = 0; i < 10; i++)
{
CheckBox cb = new CheckBox();
cb.Text = "text" + i;
cb.ID = Guid.newGuid().ToString();
cb.ClientIDMode = ClientIDMode.Static;
pnlEmailCheckboxes.Controls.AddAt(0, cb);
pnlEmailCheckboxes.Controls.AddAt(0, new LiteralControl("<br/>"));
cbList.Add(cb);
}
Session["checkboxes"] = cbList;
mpeEmail.Show();
}
The button that tries to retrieve the textboxes (does not work):
protected void btnSendEmail_Click(object sender, EventArgs e)
{
//the email recipients
List<string> emailRecipients = new List<string>();
List<CheckBox> cbList = (List<CheckBox>)Session["checkboxes"];
foreach (CheckBox cb in cbList)
{
CheckBox cbClient = (CheckBox) pnlEmailCheckboxes.FindControl(cb.ClientID); //I've also tried to find it by cb.ID
//null reference here, the checkbox cbClient was not found
if (cbClient.Checked) emailRecipients.Add(cb.Text.Trim());
}
//Ive also tried this, it does not contain the dynamically generated checkboxes
//var cbControls = pnlEmailCheckboxes.Controls.OfType<CheckBox>();
}
Edit:
The client side html even shows the with the correct ID that matches the ID I'm searching for.
<input id="00e3a485-2083-4ef8-810b-6ed4fb1f62f9" type="checkbox" name="ctl00$Body$00e3a485-2083-4ef8-810b-6ed4fb1f62f9">

Try adding a unique ID to each dynamic control and setting the ClientIDMode = ClientIDMode.Static:
List<CheckBox> cbList = new List<CheckBox>();
for (int i = 0; i < 10; i++)
{
CheckBox cb = new CheckBox();
cb.ID = "DynamicCb" + i";
cb.ClientIDMode = ClientIDMode.Static;
cb.Text = "text" + i;
pnlEmailCheckboxes.Controls.AddAt(0, cb);
pnlEmailCheckboxes.Controls.AddAt(0, new LiteralControl("<br/>"));
cbList.Add(cb);
}

I've found a solution for my problem. If I add the controls in the OnInit method, I can see the checkboxes in the button click later on.
protected override void OnInit(EventArgs e)
{
List<CheckBox> cbList = new List<CheckBox>();
for (int i = 0; i < 10; i++)
{
CheckBox cb = new CheckBox();
cb.Text = "text" + i;
cb.ID = Guid.newGuid().ToString();
pnlEmailCheckboxes.Controls.AddAt(0, cb);
pnlEmailCheckboxes.Controls.AddAt(0, new LiteralControl("<br/>"));
cbList.Add(cb);
}
Session["checkboxes"] = cbList;
}
Another problem is present now, each checkbox always has Checked==False even when they are Checked on the UI. However, this is cause for another question.

Related

Unable to SetFocus on a dynamically created text box

I am generating the text boxes dynamically.Table rows are created dynamically too, and these text boxes are added to those dynamically created row cells and they are added to the table using the following code
protected override void OnInit(EventArgs e)
{
PopulateTextBoxes();
SetFocus();
base.OnInit(e);
}
protected void PopulateTextBoxes()
{
int quantityRequired = 0;
quantityRequired =GetQuantity();
for (int j = 0; j < quantityRequired; j++)
{
TableRow row = new TableRow();
TableCell cell1 = new TableCell();
TextBox tb = new TextBox();
tb.ID = j.ToString() +"_RowTbx"
tb.AutoPostBack = true;
tb.TextChanged += new EventHandler(tb_TextChanged);
cell1.Controls.Add(tb);
row.Cells.Add(cell1);
TableCell cell2 = new TableCell();
CheckBox chBox = new CheckBox();
chBox.CheckedChanged += new EventHandler(chBox_CheckedChanged);
chBox.AutoPostBack = true;
cell2.Controls.Add(chBox);
row.Cells.Add(cell2);
TableCell cell3 = new TableCell();
Image img = new Image();
img.Width = Unit.Pixel(25);
img.Height = Unit.Pixel(25);
img.ImageUrl = "HttpRuntime.AppDomainAppVirtualPath" + "/Images/" +"img.jpeg";
cell3.Controls.Add(img);
row.Cells.Add(cell3);
tbl_Serial.Rows.Add(row);
}
LoadDataIfExists();
}
private void tb_TextChanged(object sender, EventArgs e)
{
//I have implemented code to validate the text entered in the text box.
}
protected void SetFocus()
{
int emptytbxRow = 0;
TextBox tbx = new TextBox();
for (int i = 0; i < tbl_Serial.Rows.Count; i++)
{
string tbxId = i.ToString() + "_RowTbx";
string text = ((TextBox)tbl_Serial.Rows[i].Cells[0].FindControl(tbxId))).Text;
if (text == null || text==string.Empty)
{
tbx=((TextBox)(tbl_Serial.Rows[i].Cells[0].FindControl(tbxId)));
if (tbx != null)
tbx.Focus();
}
}
protected void LoadDataIfExists()
{
List<string> lstData=Service.GetData(int someNum)
for (int j = 0; j < lstData.Count; j++)
{
string tbxID = j.ToString() + "_RowTbx";
TextBox tbx = (TextBox)tbl_Serial.Rows[j].Cells[0].FindControl(tbxID);
tbx.Text = lstData[j];
}
}
When I debug, the tbx.focus seems to hit rightly but i do not see the cursor blinking on the text box in my UI.I do not know if I am missing something imp. Thank you.
Edit: Sorry I was not clear. When the page loads, the text boxes may contain data, but not all text boxes contain data. So whenever the page loads there are a few text boxes with data and there are empty ones. I want the cursor to be at the first empty box.
Given that you know which text box is your first empty one you want to also be aware of the page life cycle. OnInit is to early in the page life cycle for this to occur as the page is still initializing and the objects haven't yet rendered to the form. Try OnLoad or use PreRender to set focus to your item right before the form is rendered.
The link below will show you all available methods that you can hook into during the cycle.
ASP Page Lifecycle
For some unknown reason , C#code with the same logic as below did not work, while javascript works. Hope the following helps someone in future. Thank you Liqua for providing the start.
window.onload = function () {
FindWhichTextBoxIsEmpty();
}
function FindWhichTextBoxIsEmpty() {
var tableSerial = document.getElementById('tbl_Serial');
for (var i = 0; i < tableSerial.rows.length-1; i++) {
var ID = i.toString() + "_RowTbx";
if (document.getElementById(ID).value!="") {
var tb = document.getElementById(ID).value;
if (tb != "") {
if (i + 1 < tableSerial.rows.length-1) {
var nextID = (i + 1).toString() + "_RowTbx";
document.getElementById(nextID).focus();
}
}
}
}
}
didn't got your question clearly, what i got is you created a textbox dynamically, and trying to focus it at runtime.. May be this work for you try creating tb += getFocus event, or try tb.Focus();

Need to access dynamic controls ids inside the update panels

I am populating dynamic controls inside the update panel. The steps are
Step 1: Dynamic controls are populated inside dynamic table like this which is inside panel
<asp:Panel ID="pnlShowDDF" runat="server" Visible="False" ViewStateMode="Enabled">
</asp:Panel>
Step 2:
protected void loadTable()
{
HtmlTable tblDDF = new HtmlTable();
var objDDF = new ddf();
var dsDdfDetail = "DataSet Loaded"
if (dsDdfDetail.Tables[0].Rows.Count > 0)
{
int RowsCount = dsDdfDetail.Tables[0].Rows.Count;
for (int i = 0; i < RowsCount; i++)
{
HtmlTableRow tblNewRow = new HtmlTableRow();
HtmlTableCell tblDdfCell = new HtmlTableCell();
tblDdfCell1.Controls.Add(addCheckbox(dsDdfDetail.Tables[0].Rows[i][0].ToString()));
//The addCheckbox function returns the checkbox with its text
tblNewRow.Controls.Add(tblDdfCell);
tblDDF.Controls.Add(tblNewRow);
}
HtmlTableRow htFooterRow = new HtmlTableRow();
HtmlTableCell htFooterCell = new HtmlTableCell();
htFooterCell.Controls.Add(DelButton());
//DelButton() is written in below
htFooterCell.Attributes.Add("class", "pnlFooterRow");
htFooterCell.ColSpan = 2;
htFooterRow.Cells.Add(htFooterCell);
tblDDF.Controls.Add(htFooterRow);
}
pnlShowDDF.Controls.Add(tblDDF);
pnlShowDDF.Visible = true;
}
protected Button DelButton()
{
var btnDelete = new Button();
btnDelete.ID = "btnDelete";
btnDelete.Text = "De-Allocate";
btnDelete.Click += new EventHandler(btnDelete_Click);
btnDelete.Attributes.Add("class", "button");
btnDelete.ViewStateMode = ViewStateMode.Enabled;
return btnDelete;
}
Step 3 Need to access dynamic checkbox id from the btnDelete
void btnDelete_Click(object sender, EventArgs e)
{
//Need to access the checkbox id's here
foreach(Control chk in pnlShowDDF.Controls)
{
if(chk is CheckBox)
{
CheckBox chkbx= chk as CheckBox;
if(chkbx.Checked)
{
//Here i need to access the id's which i can't right now
}
}
}
}
Step 4: i have recalled the loadTable function on OnInit but no gains
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
loadTable();
}
What should be done so that i can access the checkbox id's ??
Whenever you add dynamic controls, you have to add them in Page_Init event and assign them proper IDs, so that when a postback occurs, those dynamic added controls are created again along with their values and will be accessible in other events, in your case btnDelete_Click.
So what you are missing is assigning IDs to the table cells and rows, I hope you are assigning ID to the checkboxes.
========================= EDIT ============================
Here is the code that is working with me, btnDelete_Click has good enough changes in it. I am getting the checkboxes that I added in and if I check any of them, i get the value as true.
protected void loadTable()
{
HtmlTable tblDDF = new HtmlTable();
//var objDDF = new ddf();
//DataSet dsDdfDetail = new DataSet();
//if (dsDdfDetail.Tables[0].Rows.Count > 0)
//{
//int RowsCount = dsDdfDetail.Tables[0].Rows.Count;
for (int i = 0; i < 5; i++)
{
HtmlTableRow tblNewRow = new HtmlTableRow();
HtmlTableCell tblDdfCell = new HtmlTableCell();
tblDdfCell.Controls.Add(addCheckbox(i.ToString()));
//The addCheckbox function returns the checkbox with its text
tblNewRow.Controls.Add(tblDdfCell);
tblDDF.Controls.Add(tblNewRow);
}
HtmlTableRow htFooterRow = new HtmlTableRow();
HtmlTableCell htFooterCell = new HtmlTableCell();
htFooterCell.Controls.Add(DelButton());
//DelButton() is written in below
htFooterCell.Attributes.Add("class", "pnlFooterRow");
htFooterCell.ColSpan = 2;
htFooterRow.Cells.Add(htFooterCell);
tblDDF.Controls.Add(htFooterRow);
//}
pnlShowDDF.Controls.Add(tblDDF);
pnlShowDDF.Visible = true;
}
protected Button DelButton()
{
var btnDelete = new Button();
btnDelete.ID = "btnDelete";
btnDelete.Text = "De-Allocate";
btnDelete.Click += new EventHandler(btnDelete_Click);
btnDelete.Attributes.Add("class", "button");
//btnDelete.ViewStateMode = ViewStateMode.Enabled;
return btnDelete;
}
protected CheckBox addCheckbox(string id)
{
CheckBox chk = new CheckBox();
chk.ID = id;
return chk;
}
void btnDelete_Click(object sender, EventArgs e)
{
//Need to access the checkbox id's here
foreach (Control chk in pnlShowDDF.Controls)
{
if (chk is HtmlTable)
{
HtmlTable tbl = (HtmlTable)chk;
foreach (HtmlTableRow row in tbl.Rows)
{
foreach (HtmlTableCell cell in row.Cells)
{
foreach (Control chk1 in cell.Controls)
{
if (chk1 is CheckBox)
{
CheckBox chkbx = chk1 as CheckBox;
if (chkbx.Checked)
{
//Here i need to access the id's which i can't right now
}
}
}
}
}
}
}
}

Dynamically generated Button click not getting called?

I have associated a Button ID while generating Buttons dynamically and created a Button event handler as follows:
btn.Click += new EventHandler(btn_Click);
Button Click event:
protected void btn_Click(object sender,EventArgs e)
{
Button b = new Button();
b = (Button)sender;
string i = b.ID.Substring(b.ID.Length - 1, 1);
int j1 =Convert.ToInt32(i);
id1 = to[j1];
Page.ClientScript.RegisterClientScriptBlock(Type.GetType("System.String"),
"addScript", "PassValues('" + id1 + "')", true);
ScriptManager.RegisterStartupScript(this, this.GetType(),
"sendMessage", "javascript:sendMessage(); ", true);
}
However this event is not getting called i have placed all my controls inside an UpdatePanel
EDIT: What is happening is on button click somehow a function is getting called which is present on Page.Load
protected void getEntriesRight()
{
j = (int)Session["j"];
int n1 = j + 3;
for (; j <= n1; j++)
{
if (j < fr.data.Length)
{
HtmlGenericControl listItem = new HtmlGenericControl("li");
HtmlGenericControl a1 = new HtmlGenericControl("a");
Label anchor = new Label();
Image im = new Image();
btn = new Button();
im.ImageUrl = fr.data[j].pic_square;
im.Height = 45;
im.Width = 47;
btn.CssClass = "btn-add";
btn.Text = "Invite";
to[j] = fr.data[j].uid;
btn.ID = "btn" + j;
a1.Attributes.Add("href", "#");
anchor.Text = fr.data[j].name;
a1.Controls.Add(btn);
a1.Controls.Add(im);
a1.Controls.Add(anchor);
listItem.Controls.Add(a1);
list.Controls.Add(listItem);
btn.Click += new EventHandler(btn_Click);
}
}
Session["j"] = j;
}
Help!
Dynamically generated controls have to be recreated on every postback in order for their events to fire. This is one of the most commonly-encountered problems with generating controls programmatically in .NET, and it is discouraged if you can find a way around it.
For example, if you have a button that should only be present when another button is clicked, have the button in the page to begin with, and use the Visible property to control whether it is shown or not.
Regarding your edit. Every post-back to the server, even inside an UpdatePanel, is going to call Page_Load. If you want to detect whether a request has come from an UpdatePanel then you need to check !Page.IsAsync before calling the function.

dynamic dropdownlist in asp.net

I created dropdownlist at runtime when a button is clicked.and i palced another button to get the selected text from dynamic dropdownlist.When i try to retrieve the selected text from dropdownlist it gives me the error called object reference not set, following is my code.
TableRow tr;
TableCell tc;
DropDownList dp;
TextBox txt;
protected void Button1_Click(object sender, EventArgs e)
{
int no = int.Parse(TextBox1.Text);
for (int i = 0; i < no; i++)
{
tr = new TableRow();
tr.BorderStyle = BorderStyle.Groove;
for (int j = 0; j < 1; j++)
{
tc = new TableCell();
tc.BorderStyle = BorderStyle.Groove;
dp = new DropDownList();
//form1.Controls.Add(dp);
txt = new TextBox();
dp.Items.Add("hello");
tc.Controls.Add(dp);
tc.Controls.Add(txt);
tr.Cells.Add(tc);
}
Table1.Rows.Add(tr);
}
}
protected void Button2_Click(object sender, EventArgs e)
{
TextBox1.Text =((DropDownList)this.FindControl("dp")).SelectedItem.Text;
}
You can't do it this way. Remember that on every request, you get a new page object, and new copies of all the controls in it. Any control you add dynamically must be added the same way every single time, otherwise it won't exist.
In this case, you add it once, when the button is clicked. When you click button2, a request is generated and a new page object is created that no longer has your dropdownlist, because it is only ever added in the button1 handler.
The easiest thing to do would be add your dropdownlist to the page normally but just set Visible to false. Then when they click button 1, set Visible to true. This will ensure that your dropdownlist will always be present.
Dynamic controls are tricky, and should be avoided when possible, especially if you're new to ASP.Net.
Actually, I was able to make it work..
I created a dataset ahead of the table creation, then:
tc = new TableCell();
dd= new DropDownList();
ddl.ID = dd1;
foreach (DataRow dr in dst.Tables[0].Rows)
{
ddl.Items.Add(new ListItem(dr["Text"].ToString(),dr["Value"].ToString()));
}
tcActions.Controls.Add(ddlActions);
I'm not an expert or anything, I just peck at it until I make it do what I want.

Adding new eventHandler in RadioButton CheckedChanges in dynamic table

I'm trying to add another eventHandler to RadioButton. This is the sample code (which is working):
ASP.NET:
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
<asp:Button ID="Button1" runat="server" Text="Button" />
C#:
protected void Page_Load(object sender, EventArgs e)
{
RadioButton RB1 = new RadioButton();
RB1.ID = "1";
RB1.GroupName = "bla";
RB1.CheckedChanged += new EventHandler(CheckedChanged);
RadioButton RB2 = new RadioButton();
RB2.ID = "2";
RB2.GroupName = "bla";
RB2.CheckedChanged += new EventHandler(CheckedChanged);
PlaceHolder1.Controls.Add(RB1);
PlaceHolder1.Controls.Add(RB2);
}
protected void CheckedChanged(object sender, EventArgs e)
{
Label1.Text = ((RadioButton)sender).ID;
}
In my project I have dynamic creating of RadioButtons (the number of rows I get from database). The same adding eventHandler does not work, but if I write
MyRadioButton.Load += new EventHandler(Another_method);
The Another_method will start, but in
MyRadioButton.CheckedChanged += new EventHandler(Main_method);
the Main_method will not start if I choose one of the RadioButtons.
What is wrong?
#KevinP
This is my code:
Table tb1 = new Table();
PlaceHolder1.Controls.Add(tb1);
TableRow tr = new TableRow();
TableCell tc = new TableCell();
//adding the first row with title"
tr.Cells.Add(tc);
for (int i = 0; i < ((ArrayList)(result[0])).Count; i++)
{
tc = new TableCell();
Label example = new Label();
example.Text = ((columnsResultFromSqlClients)(i)).ToString();
tc.Controls.Add(example);
tr.Cells.Add(tc);
}
tb1.Rows.Add(tr);
//filling the table
for (int i = 0; i < result.Count; i++)
{
tr = new TableRow();
tc = new TableCell();
//adding radio button
RadioButton RB = new RadioButton();
RB.Attributes.Add("value", ((ArrayList)(result[i]))[0].ToString());
RB.GroupName = "for_selecting";
RB.ID = ((ArrayList)(result[i]))[0].ToString();
RB.CheckedChanged += new EventHandler(RB_CheckedChanged2);
//RB.AutoPostBack = true;
RB.Attributes.Add("AutoPostBack", "True");
tc.Controls.Add(RB);
tr.Cells.Add(tc);
//adding content
for (int j = 0; j < ((ArrayList)(result[i])).Count; j++)
{
tc = new TableCell();
Label example = new Label();
example.Text = ((ArrayList)(result[i]))[j].ToString();
tc.Controls.Add(example);
tr.Cells.Add(tc);
}
tb1.Rows.Add(tr);
}
If I use RB.AutoPostBack = true;, I have no time to press the button to submit my choice, cause the page will reload when i click the one of the Radio Buttons.
Also the RB_CheckedChanged2 code:
protected void RB_CheckedChanged2(object sender, EventArgs e)
{
RadioButton tempRB = (RadioButton)sender;
if (tempRB.Checked)
{
selected_id = tempRB.ID;
}
}
The select_id is a static int varible with standart value = "-1".
If I am not mistaken, with dynamic controls in ASP.Net, you need to "rewire" their events on a postback. Remember that on a postback, dynamic controls are no longer there. You have to recreate them.

Categories