failing to locate controls from code behind. - c#

I'm having a problem to get controls/ controls id that I have created manually from code behind. after doing research I found if I create the table and its all component including any controls in Page_Init() method, when rendering after postback the text value of textbox control should be available to the page. i tried to locate the textbox control using FindControl() method. when debugging it only reach to the line where I tried to locate the control using FindControl() and then throw an exception "Object reference not set to an instance of an object" bellow is the Page_Init() method
protected void Page_Init(object sender, EventArgs e)
{
Table tb = new Table();
tb.ID = "Table1";
TableRow row1 = new TableRow();
TableCell cell1 = new TableCell();
TableCell cell2 = new TableCell();
TableCell cell3 = new TableCell();
TextBox txtbx = new TextBox();
Button btn = new Button();
cell1.Text = "Name: ";
txtbx.ID = "table1_text_input";
txtbx.ValidationGroup = "rosy";
cell2.Controls.Add(txtbx);
btn.Text = "Get the input";
btn.ValidationGroup = "rosy";
btn.Click += getBoxinput_Click;
cell3.Controls.Add(btn);
// adding cells to row1
row1.Cells.Add(cell1);
row1.Cells.Add(cell2);
row1.Cells.Add(cell3);
// adding row to table1
tb.Rows.Add(row1);
Panel1.Controls.Add(tb);
}
below is the button click event that supposes to display the control id and its text. I'm stuck with this for the last couple of days. any help will be appreciated.
protected void getBoxinput_Click(object sender, EventArgs e)
{
try
{
if (IsPostBack)
{
Table t = (Table)Page.FindControl("Panel1").FindControl("Table1");
TextBox tbox;
foreach (TableRow tr in t.Rows)
{
foreach (TableCell tc in tr.Cells)
{
foreach (Control cnt in tc.Controls)
{
if (cnt.GetType() == typeof(TextBox))
{
tbox = (TextBox)cnt;
display.Text += "control id: " + tbox.ID + " control input: " + tbox.Text + "<br/>";
}
}
}
}
}
}
catch (NullReferenceException ex)
{
display.Text += ex.Message;
}
}

Maybe I am missing something but why don't you just put all the controls in the global scope of the class (instead of just creating the instances inside Page_Init) so that you can access them in any part of your class. Of course I am assuming that Page_Init and getBoxinput_Click are in the same class.
EDIT:
Here is the example on how to put the variables in the global scope:
Table tb; //Declare variables outside any function.
protected void getBoxinput_Click(object sender, EventArgs e)
{
tb = new Table(); //Initialize them inside a function.
}
This way you will be able to access tb inside any function.

Your code is working perfectly. Here is what I used for the form markup:
<form id="form1" runat="server">
<asp:Panel ID="Panel1" runat="server"></asp:Panel>
<asp:Label ID="display" runat="server"></asp:Label>
</form>

Related

TextChanged event fires but does not run in code behind

In my aspx file I have the following code:
<asp:PlaceHolder ID="phdHolding" runat="server">
<asp:Label ID="lblWarning" runat="server" Text="" Visible="false" />
<asp:PlaceHolder ID="phdInput" runat="server" Visible="false">
<h3><asp:Label ID="lblArea" runat="server" Text="Area" /></h3>
</asp:PlaceHolder>
</asp:PlaceHolder>
In code behind (c#) I create a table which is added to phdInput. One part of that code is the creation and population of a TextBox (and Label) within a Table Cell. The TextBox is required to call a function on TextChanged.
decimal amount = Convert.ToDecimal(dc.DataScalar("SELECT Item" + rownr + " FROM Companies WHERE CompanyName='" + coy + "' AND BusinessUnit='" + bu + "'"));
TextBox tb = new TextBox(); tb.ID = "txtAmount" + rownr; tb.Width = 70; tb.Text = amount.ToString("N0");
tb.AutoPostBack = true; tb.TextChanged += new EventHandler(UpdateAmounts);
Label lbl = new Label(); lbl.Text= " " + trow["Unit"].ToString();
TableCell tdamount = new TableCell(); tdamount.Controls.Add(tb); tdamount.Controls.Add(lbl);
tr2.Cells.Add(tdamount);
This is all working fine and everything is displayed on the page. However, when the text is changed and you click outside the textbox or press'Enter' etc. the function is not being reached (have checked in VS) and phdInput becomes blank.
I have used this function, and the TextChanged method of calling it, before with no issues so why is it not working now?
I have managed to recreate one problem
phdInput becomes blank
This was suspicious, if it disappears there must be PostBack in the action. Suspicion rises especially because phdInput attribute Visible is set to false on the form.
I suppose form's initialization is happening inside the Page_Load method and one of the code behind lines is to set phdInput attribute Visible to true. However, phdInput disappears after PostBack is fired, so there's probably check
if (!IsPostBack)
Initialization is happening inside of it, which is correct, no need to initialize it every time page reloads. However
phdInput.Visible = true;
should be outside of check if (!IsPostBack) in order to phdInput be always visible.
Next, something fires the PostBack.
However, when the text is changed and you click outside the textbox or
press'Enter' etc. the function is not being reached (have checked in
VS) and phdInput becomes blank.
This sounds like TextChanged event works, it only calls some other event handler.
I hope it will help you find the solution. Here follows the code that recreates the issue phdInput becomes blank (it is poorly written).
.aspx - content of body tag
<form id="form1" runat="server">
<div>
<p>start</p>
<asp:PlaceHolder ID="phdHolding" runat="server">
<asp:Label ID="lblWarning" runat="server" Text="" Visible="false" />
<asp:PlaceHolder ID="phdInput" runat="server" Visible="false" >
<h3><asp:Label ID="lblArea" runat="server" Text="Area" /></h3>
</asp:PlaceHolder>
</asp:PlaceHolder>
<p>end</p>
</div>
</form>
code behind
using System;
using System.Web.UI.WebControls;
namespace WebApplication8
{
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
try
{
if (!IsPostBack)
{
// row 1
int rownr = Convert.ToInt32(1);
TableRow tr = new TableRow();
tr.VerticalAlign = VerticalAlign.Top;
TableCell tdtype = new TableCell();
tdtype.Text = "table cell 1 text";
tdtype.Width = 250;
tdtype.HorizontalAlign = HorizontalAlign.Left;
tr.Cells.Add(tdtype);
decimal amount = Convert.ToDecimal(1);
TextBox tb = new TextBox(); tb.ID = "txtAmount" + rownr; tb.Width = 70; tb.Text = amount.ToString("N0");
tb.AutoPostBack = true; tb.TextChanged += new EventHandler(UpdateAmounts);
Label lbl = new Label(); lbl.Text = " " + "1";
TableCell tdamount = new TableCell(); tdamount.Controls.Add(tb); tdamount.Controls.Add(lbl);
tr.Cells.Add(tdamount);
// row 2
int rownr2 = Convert.ToInt32(2);
TableRow tr2 = new TableRow();
tr2.VerticalAlign = VerticalAlign.Top;
TableCell tdtype2 = new TableCell();
tdtype2.Text = "table cell 2 text";
tdtype2.Width = 250;
tdtype2.HorizontalAlign = HorizontalAlign.Left;
tr2.Cells.Add(tdtype2);
decimal amount2 = Convert.ToDecimal(2);
TextBox tb2 = new TextBox(); tb2.ID = "txtAmount" + rownr2; tb2.Width = 70; tb2.Text = amount2.ToString("N0");
tb2.AutoPostBack = true; tb2.TextChanged += new EventHandler(UpdateAmounts);
Label lbl2 = new Label(); lbl2.Text = " " + "2";
TableCell tdamount2 = new TableCell(); tdamount2.Controls.Add(tb2); tdamount2.Controls.Add(lbl2);
tr2.Cells.Add(tdamount2);
// table
var table = new Table();
table.Rows.Add(tr);
table.Rows.Add(tr2);
phdInput.Controls.Add(table);
lblWarning.Text = "some warning";
lblArea.Text = "some area text";
lblWarning.Visible = true;
phdInput.Visible = true;
}
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
}
protected void UpdateAmounts(object sender, EventArgs e)
{
}
}
}
when page is opened
after textbox's text is changed - either one

find dynamically added controls

I'm adding dropdownlists to my page depending on a amount of database entries and when I press the button I want to get the selected values in each dropdownlist.
I tried this
foreach(DropDownList a in Form.Controls.OfType<DropDownList>())
{
Response.Write(a.SelectedValue);
}
but it doesn't find any dropdownlist on the page. Below is the code I use to add the dorpdownlists.
protected void Page_Init()
{
string product = Request.QueryString["product"];
foreach (productoption r in dbcon.GetOption(product))
{
TableRow row = new TableRow();
TableCell cel1 = new TableCell();
TableCell cel2 = new TableCell();
DropDownList dropdown1 = new DropDownList();
dropdown1.CssClass = "productdropdown";
foreach (suboption f in dbcon.GetSubOption(r.ProductOptionID))
{
dropdown1.Items.Add(f.SubOptionName + " +$" +f.SubOptionPrice);
}
cel1.Text = "<b>" + r.OptionName + "</b>";
cel2.Controls.Add(dropdown1);
row.Cells.Add(cel1);
row.Cells.Add(cel2);
Table1.Rows.Add(row);
}
TableRow row2 = new TableRow();
TableCell cell3 = new TableCell();
Button cartbutton = new Button();
cartbutton.ID = product;
cartbutton.CssClass = "btn_addcart";
cartbutton.Click += cartbutton_OnClick;
cartbutton.Text = "Add to cart";
cell3.Controls.Add(cartbutton);
row2.Cells.Add(cell3);
Table1.Rows.Add(row2);
}
foreach (TabelRow row in Table1.Rows)
{
if(row.Cells.Count > 0)
{
if (row.Cells[1].Controls.Count > 0 && row.Cells[1].Controls[0].GetType() == typeof(DropDownList))
{
Response.Write(a.SelectedValue);
}
}
}
First you should make a function that looks for a control type in a ControlCollection and returns a list of found controls. Something like that:
public List<T> GetControlsOfType<T>(ControlCollection controls)
{
List<T> ret = new List<T>();
try
{
foreach (Control control in controls)
{
if (control is T)
ret.Add((T)((object)control));
else if (control.Controls.Count > 0)
ret.AddRange(GetControlsOfType<T>(control.Controls));
}
}
catch (Exception ex)
{
//Log the exception
}
return ret;
}
and then you can get all DropDownList like that:
List<DropDownList> ret = GetControlsOfType<DropDownList>(this.Page.Controls);
I hope it helped.
You should be adding controls inside another control for example a panel
*Also you dont need to define controls at page init, you can do that at page load and they will retain their value*
protected void Page_Load(object sender, EventArgs e)
{
loadControls();
}
//For Instance lets take a dropdownlist and add it to a panel named testpanel
Protected void loadControls()
{
DropdownList ddlDynamic = new DropdownList();
//give this control an id
ddlDynamic.Id = "ddlDynamic1"; // this id is very important as the control can be found with same id
//add data to dropdownlist
//adding to the panel
testpanel.Controls.Add(ddlDynamic);
}
//Now we have to find this control on post back for instance a button click
protected void btnPreviousSet_Click(object sender, EventArgs e)
{
//this will find the control here
//we will you the same id used while creating control
DropdownList ddlDynamic1 = testpanel.FindControl("ddlDynamic1") as DropdownList;
//can resume your operation here
}

how to delete dynamic created textbox controls on dropdownlist selectedIndexChanged event and recreate new dynamic control on new selected value

Aspx page:
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<asp:placeholder id="container" runat="server" visible="false"></asp:placeholder>
</td>
</tr>
</table>
On Code Behind file:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
generateDynamicControls();
}
private void generateDynamicControls()
{
for (int i = 0; i < dt.Rows.Count; i++)
{
HtmlGenericControl tr = new HtmlGenericControl("tr");
HtmlGenericControl td1 = new HtmlGenericControl("td");
Label lbl = new Label();
lbl.ID = "lbl" + dt.Rows[i]["sSubjectName"].ToString();
lbl.Text = dt.Rows[i]["sSubjectName"].ToString() + " :";
lbl.Width = new Unit(170);
lbl.Style.Add("padding-left", "10px");
lbl.Style.Add("font-weight", "bold");
td1.Controls.Add(lbl);
tr.Controls.Add(td1);
HtmlGenericControl td2 = new HtmlGenericControl("td");
TextBox txtBox = new TextBox();
txtBox.ID = "txt" + dt.Rows[i]["sSubjectName"].ToString();
txtBox.CssClass = "TxtBox";
txtBox.TextMode = TextBoxMode.MultiLine;
txtBox.Width = new Unit(840);
td2.Style.Add("colspan", "3");
td2.Controls.Add(txtBox);
tr.Controls.Add(td2);
container.Controls.Add(tr);
HtmlGenericControl tr1 = new HtmlGenericControl("tr");
HtmlGenericControl td3 = new HtmlGenericControl("td");
td3.Style.Add("colspan", "4");
td3.InnerHtml = " ";
tr1.Controls.Add(td3);
container.Controls.Add(tr1);
//container.Controls.Add(new LiteralControl("<br />"));
//LiteralControl literalBreak = new LiteralControl();
//literalBreak.Text ="</br>";
}
container.Visible = true;
}
}
`dt(datatable)` is filled from other function.
this is working fine and controls are created correclty.
But I want to recreate this dynamic controls on selected change event of dropdownlist. but before recreate these controls i have to delete previously created controls.
I have tried below code in dropdownlist selected changed event to delete these controls and recreate new controls.
for (int i = 0; i < dt.Rows.Count; i++)
{
container.Controls.Remove(container.FindControl(dt.Rows[i]["nSubjectId"].ToString()));
}
generateDynamicControls();
But it's not work and give me following error. becuase of onload event is alread ycalled first and created the dyanmic controls.
Multiple controls with the same ID 'lblOrals' were found. FindControl requires that controls have unique IDs.
How can I solve this problem.
Please help me solve this problem.
Thanks in advance
Try this
Give the for loop variable (i) to your label id, like the below way
lbl.ID = "lbl" + dt.Rows[i]["sSubjectName"].ToString()
+i.ToString();//i is loop variable for coordinated with labelid.
Now if the "dt.Rows[i]["sSubjectName"]" is return "LabeleName", When the for loop will assign the values like
dt.Rows[i]["sSubjectName"].ToString() + i.ToString() , So It is return values like "LabeleName1"
Finally you got the label id's are followings name
lblLabeleName1
lblLabeleName2
lblLabeleName3
.
.
.
.etc
textbox are like
txtBox.ID = "txt" + dt.Rows[i]["sSubjectName"].ToString() + i.ToString();
Result are
txtLabeleName1
txtLabeleName2
txtLabeleName3
.
.
.
etc.
Remove fields code like
//For label
container.Controls.Remove(container.FindControl("lbl" + dt.Rows[i]["sSubjectName"].ToString() +i.ToString()));
//For TextBox
container.Controls.Remove("txt" + dt.Rows[i]["sSubjectName"].ToString()+ i.ToString() ));
And Should call the generateDynamicControls(); method inside of !ISPostBack() event in page load event
Like
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if(!IsPostBack)
{
generateDynamicControls();
}
}

How to dynamically assign "is-active" class based on current focus in C#

I have a class called "is-active" and it has a colored arrow that sticks out from the nav into the main content based on which link is the current active one. The code runs a foreach and pulls all the categories from the database. How do I get the "is-active" class to display only for the current link? I know it works since I put it in the openList control and it displayed on all five categories, I just don't know how to get it to display on only the selected category.
Thank you in advance for your help!
Below is my code for the categories and link button:
protected override void CreateChildControls()
{
LiteralControl openingDiv = new LiteralControl("<div id='MainPanel'>");
LiteralControl closingDiv = new LiteralControl("</div>");
this.Controls.Add(openingDiv);
foreach (DataRow dr in ds.Tables[0].Rows)
{
LiteralControl openList = new LiteralControl("<li class='" + dr["CategoryColor"].ToString() + "'>");
LiteralControl closeList = new LiteralControl("</li>");
Label lblNumber = new Label();
LinkButton myLinkButton = new LinkButton();
myLinkButton.Text = "<span class='number'>" + dr["CategoryNumber"] + "</span>"+ dr["CategoryName"].ToString();
myLinkButton.CommandArgument = dr["Category_ID"].ToString();
myLinkButton.Click += myLinkButton_Click;
this.Controls.Add(openList);
this.Controls.Add(myLinkButton);
this.Controls.Add(closeList);
}
this.Controls.Add(closingDiv);
}
void myLinkButton_Click(object sender, EventArgs e)
{
LinkButton btn = (LinkButton)(sender);
Session["CategoryID"] = btn.CommandArgument;
Response.Redirect(Request.RawUrl);
}

add text box dynamically and capture data on button click

I am adding text boxes dynamically and trying to capture data entered in text box on button click. but what is happening is , though I entered the data in the text box, when I clicked the button, the page is getting loaded and the control is getting created again. As a result , I am loosing the data in the text box. Can you tell me how can I capture this data entered to the dynamically created text boxes.
My sample code is as follows:
protected void Page_Load(object sender, EventArgs e)
{
Table tblTextboxes = new Table();
for(int i=0;i<10;i++)
{
TableRow tr=new TableRow();
TableCell tc=new TableCell();
TextBox tb=new TextBox();
tb.ID=i.ToString();
tc.Controls.Add(tb);
tr.Cells.Add(tc);
TableCell tc1=new TableCell();
LinkButton lnk=new LinkButton();
lnk.ID=i.ToString()+tb.Text+"lnk";
lnk.Text = "Show";
lnk.Click+=new EventHandler(lnk_Click);
tc1.Controls.Add(lnk);
tr.Cells.Add(tc1);
tblTextboxes.Rows.Add(tr);
}
placeTest.Controls.Add(tblTextboxes);
}
void lnk_Click(object sender, EventArgs e)
{
LinkButton lnk=sender as LinkButton;
Label lbl=new Label();
lbl.Text="The text is"+lnk.ID;
placeTest.Controls.Add(lbl);
}
LinkButton ID is changed every time you enter text into TextBox and post back.
One thing you want to make sure when creating control dynamically is - you want to recreate them with same ID when post back.
Updated Solution (to retrieve text from TextBox)
protected void Page_Load(object sender, EventArgs e)
{
var tblTextboxes = new Table();
for (int i = 0; i < 10; i++)
{
var tr = new TableRow();
var tc = new TableCell();
var tb = new TextBox {ID = i.ToString()};
tc.Controls.Add(tb);
tr.Cells.Add(tc);
var tc1 = new TableCell();
// This is a fix for - lnk.ID=i.ToString()+tb.Text+"lnk";
var lnk = new LinkButton {ID = i + "lnk", Text = "Show"};
lnk.Click += lnk_Click;
tc1.Controls.Add(lnk);
tr.Cells.Add(tc1);
tblTextboxes.Rows.Add(tr);
}
placeTest.Controls.Add(tblTextboxes);
}
void lnk_Click(object sender, EventArgs e)
{
var lnk = sender as LinkButton;
var lbl = new Label();
lbl.Text = "LinkButton ID: " + lnk.ID;
// Get number value from string
string id = Regex.Replace(lnk.ID, #"[^\d]", "");
// Retrieves a TextBox control by ID
var control = FindControlRecursive(Page, id);
if (control != null)
{
var textbox = control as TextBox;
lbl.Text += "; TextBox Text: " + textbox.Text;
}
placeTest.Controls.Add(lbl);
}
public Control FindControlRecursive(Control root, string id)
{
if (root.ID == id)
return root;
return root.Controls.Cast<Control>()
.Select(c => FindControlRecursive(c, id))
.FirstOrDefault(c => c != null);
}
Based on the MSDN, I would recommend to use Page class's Init event. Look in to the title View State and Dynamically Added Controls for explanation. Also, I would recommend to add dynamic controls at the end of all existing controls. Create table first, and then add the text boxes.
I modified your code. It worked for me. I used VS 2012, .Net 4.5
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(DateTime.Now.ToString());
}
protected void Page_Init(object sender, EventArgs e)
{
Table tblTextboxes = new Table();
for (int i = 0; i < 10; i++)
{
TableRow tr = new TableRow();
TableCell tc = new TableCell();
TextBox tb = new TextBox();
tb.ID = i.ToString();
tc.Controls.Add(tb);
tr.Cells.Add(tc);
//TableCell tc1 = new TableCell();
//LinkButton lnk = new LinkButton();
//lnk.ID = i.ToString() + tb.Text + "lnk";
//lnk.Text = "Show";
//lnk.Click += new EventHandler(lnk_Click);
//tc1.Controls.Add(lnk);
//tr.Cells.Add(tc1);
tblTextboxes.Rows.Add(tr);
}
placeTest.Controls.Add(tblTextboxes);
}
protected void Button1_Click(object sender, EventArgs e)
{
}

Categories

Resources