My code generates an TextBox on the fly in C# (page_load function). Can I access it in the code later? It does give me compilation error and does not seem to work. Can someone verify ?
Code for additonal problem
aContent += "<table>";
aContent += "<tr><td>lablel </td><td style='bla blah'><input type='textbox' id='col-1' name='col-1'/></td></tr> ... 10 such rows here
</table>"
spanMap.InnerHtml = aContent;
The contents are rendered OK but recusrive iteration does not return the textbox. I am calling it like this
TextBox txt = (TextBox)this.FindControlRecursive(spanMap, "col-1");
// txt = (TextBox) spanMapping.FindControl("col-1"); this does not work too
if (txt != null)
{
txt.Text = "A";
}
Assuming that you're persisting it correctly, you should be able to access it in code-behind using the FindControl method. Depending on where the control is, you may have to search recursively through the control hierarchy:
private Control FindControlRecursive(Control root, string id)
{
if (root.ID == id)
{
return root;
}
foreach (Control c in root.Controls)
{
Control t = FindControlRecursive(c, id);
if (t != null)
{
return t;
}
}
return null;
}
Using FindControlRecursive:
TextBox txt = this.FindControlRecursive(Page.Form, "TextBox1") as TextBox;
if (txt != null)
{
string text = txt.Text;
}
If you still can't find it using the above method, make sure that you're creating the control during after every postback, somwhere before Page_Load, like OnInit.
EDIT
I think you need to change the way you're adding content to the container. Instead of using a <span>, I would use a Panel, and instead of building markup, simply add controls to the panel in code-behind:
TextBox txt = new TextBox();
txt.ID = String.Format("txt_{0}", Panel1.Controls.Count);
Panel1.Controls.Add(txt);
Here's an example:
<%# Page Language="C#" %>
<script type="text/C#" runat="server">
protected void Page_Load(object sender, EventArgs e)
{
var textBox = new TextBox();
textBox.ID = "myTextBox";
textBox.Text = "hello";
Form1.Controls.Add(textBox);
}
protected void BtnTestClick(object sender, EventArgs e)
{
var textBox = (TextBox)Form1.FindControl("myTextBox");
lblTest.Text = textBox.Text;
}
</script>
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<form id="Form1" runat="server">
<asp:LinkButton ID="btnTest" runat="server" Text="Click me" OnClick="BtnTestClick" />
<asp:Label ID="lblTest" runat="server" />
</form>
</body>
</html>
Related
Actually, I am Creating 1 TextBox on Pageload and adding that TextBox to Panel.
Now, I have a LinkButton like Add Another.
I am entering Text in that TextBox and if needed I need to Create New TextBox,by clicking Add Another LinkButton.
Actually, I am able to get the count and recreate the TextBoxes.
But,the Problem is that, My Entered text in the Previously Generated Textboxes is Missing.
Can Anyone,Suggest me a solution for this?
protected void Page_Load(object sender, EventArgs e)
{
try
{
if (!IsPostBack)
{
for (int i = 0; i < 5; i++)
{
TableRow row = new TableRow();
for (int j = 0; j < 5; j++)
{
TableCell cell = new TableCell();
TextBox tb = new TextBox();
tb.ID = "TextBoxRow_" + i + "Col_" + j;
cell.Controls.Add(tb);
row.Cells.Add(cell);
}
Table1.Rows.Add(row);
}
}
}
catch (Exception ex)
{
throw;
}
}
This is a Sample Code, the same code is written in Button_Click Also
protected void ASPxButton1_Click(object sender, EventArgs e)
{
int k = Table1.Controls.Count;
}
I am getting a Count=0 on Button_Click.
All you need to do is to re-instantiate / reinitialize dynamic controls before or within page load event each and every time during postback and add this control to page / forms / placeholders. Then, the posted data will automatically be assigned to the control by calling the LoadPostData method by the parent control.
check the article and how to write code for dynamic control -
How to maintain dynamic control events, data during postback in asp.net
When using dynamic controls, you must remember that they will exist only until the next postback.ASP.NET will not re-create a dynamically added control. If you need to re-create a control multiple times, you should perform the control creation in the PageLoad event handler ( As currently you are just creating only for first time the TextBox using Condition: !IsPostabck ). This has the additional benefit of allowing you to use view state with your dynamic control. Even though view state is normally restored before the Page.Load event, if you create a control in the handler for the PageLoad event, ASP.NET will apply any view state information that it has after the PageLoad event handler ends.
So, Remove the Condition: !IsPostback, So that each time the page Loads, The TextBox control is also created. You will also see the State of Text box saved after PageLoad handler completes. [ Obviously you have not disabled ViewState!!! ]
Example:
protected void Page_Load(object sender, EventArgs e)
{
TextBox txtBox = new TextBox();
// Assign some text and an ID so you can retrieve it later.
txtBox.ID = "newButton";
PlaceHolder1.Controls.Add(txtBox);
}
Now after running it, type anything in text box and see what happens when you click any button that causes postback. The Text Box still has maintained its State!!!
The dynamically generated control do not maintain state. You have to maintain it at your own. You can use some hidden field to keep the state of controls, which will be used on server side to extract the state. Asp.net uses hidden field to maintain the state between requests, you can see __VIEWSTATE in the source.
In ASP.NET pages, the view state represents the state of the page when
it was last processed on the server. It's used to build a call context
and retain values across two successive requests for the same page. By
default, the state is persisted on the client using a hidden field
added to the page and is restored on the server before the page
request is processed. The view state travels back and forth with the
page itself, but does not represent or contain any information that's
relevant to client-side page display, Reference.
Just remove this line
if (!IsPostBack)
This is My final answer after working a lot with Dynamic Controls
.aspx
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<div style="text-align: center">
<div style="background-color: Aqua; width: 250px;">
<br />
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:PlaceHolder runat="server" ID="myPlaceHolder"></asp:PlaceHolder>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="btnAddTextBox" EventName="Click" />
</Triggers>
</asp:UpdatePanel>
<br />
</div>
<br />
<asp:Button ID="btnAddTextBox" runat="server" Text="Add TextBox" OnClick="btnAddTextBox_Click" />
<br /><br />
<asp:UpdatePanel ID="UpdatePanel2" runat="server">
<ContentTemplate>
<asp:Button runat="server" ID="MyButton" Text="Get Values." OnClick="MyButton_Click" />
<br /><br />
<asp:Label runat="server" ID="MyLabel"></asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
</div>
</form>
.aspx.cs
static int myCount = 0;
private TextBox[] dynamicTextBoxes;
protected void Page_PreInit(object sender, EventArgs e)
{
Control myControl = GetPostBackControl(this.Page);
if ((myControl != null))
{
if ((myControl.ClientID.ToString() == "btnAddTextBox"))
{
myCount = myCount + 1;
}
}
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
dynamicTextBoxes = new TextBox[myCount];
int i;
for (i = 0; i < myCount; i += 1)
{
TextBox textBox = new TextBox();
textBox.ID = "myTextBox" + i.ToString();
myPlaceHolder.Controls.Add(textBox);
dynamicTextBoxes[i] = textBox;
LiteralControl literalBreak = new LiteralControl("<br />");
myPlaceHolder.Controls.Add(literalBreak);
}
}
protected void btnAddTextBox_Click(object sender, EventArgs e)
{
// Handled in preInit due to event sequencing.
}
protected void MyButton_Click(object sender, EventArgs e)
{
MyLabel.Text = "";
foreach (TextBox tb in dynamicTextBoxes)
{
MyLabel.Text += tb.Text + " :: ";
}
}
public static Control GetPostBackControl(Page thePage)
{
Control myControl = null;
string ctrlName = thePage.Request.Params.Get("__EVENTTARGET");
if (((ctrlName != null) & (ctrlName != string.Empty)))
{
myControl = thePage.FindControl(ctrlName);
}
else
{
foreach (string Item in thePage.Request.Form)
{
Control c = thePage.FindControl(Item);
if (((c) is System.Web.UI.WebControls.Button))
{
myControl = c;
}
}
}
return myControl;
}
When you are working with dynamic controls they will not able to maintain its state during postback and their data lost Cause they dont have any viewstate to maintain their data.
You only need to maintain the created controls data into ViewState
dynamically and loads the data into page at the time of postback and you
done.
public Dictionary<Guid, string> UcList
{
get { return ViewState["MyUcIds"] != null ? (Dictionary<Guid, string>)ViewState["MyUcIds"] : new Dictionary<Guid, string>(); }
set { ViewState["MyUcIds"] = value; }
}
public void InitializeUC()
{
int index = 1;
foreach (var item in UcList)
{
var myUc = (UserControls_uc_MyUserControl)LoadControl("~/UserControls/uc_MyUserControl.ascx");
myUc.ID = item.Value;
pnlMyUC.Controls.AddAt(index, myUc);
index++;
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadControl();
else
InitializeUC();
}
Actually, I have used Javascript for accomplishing my task.
and it goes like this :
<form id="form1" runat="server" enctype="multipart/form-data" method="post">
<span style="font-family: Arial">Click to add files</span>
<input id="Button1" type="button" value="add" onclick="AddFileUpload()" />
<br />
<br />
<div id="FileUploadContainer">
<!--FileUpload Controls will be added here -->
</div>
<asp:HiddenField ID="HdFirst1" runat="server" Value="" />
<br />
<asp:Button ID="btnUpload" runat="server" Text="Upload" OnClick="btnUpload_Click" />
</form>
Script :
<script type="text/javascript">
var counter = 0;
function AddFileUpload() {
var div = document.createElement('DIV');
div.innerHTML = '<input id="file' + counter + '"name = "file' + counter + '"type="text"/><input id="file' + counter + '" name = "file' + counter + '" type="file" /><input id="Button' + counter + '" type="button" value="Remove" onclick = "RemoveFileUpload(this)" />';
document.getElementById("FileUploadContainer").appendChild(div);
counter++;
}
function RemoveFileUpload(div) {
document.getElementById("FileUploadContainer").removeChild(div.parentNode);
}
function mydetails(div) {
var info;
for (var i = 0; i < counter; i++) {
var dd = document.getElementById('file' + i).value;
info = info + "~" + dd;
}
document.getElementById('<%= HdFirst1.ClientID %>').value = info;
}
</script>
and In the Upload_Click Button :
for (int i = 0; i < Request.Files.Count; i++)
{
string strname = HdFirst1.Value;
string[] txtval = strname.Split('~');
HttpPostedFile PostedFile = Request.Files[i];
if (PostedFile.ContentLength > 0)
{
string FileName = System.IO.Path.GetFileName(PostedFile.FileName);
// string textname=
//PostedFile.SaveAs(Server.MapPath("Files\\") + FileName);
}
}
I create textbox dynamically, but can't retrieve a value from created textbox. Anyone can explain to me what am I doing wrong?
HtmlGenericControl testes = new HtmlGenericControl("DIV");
testes.ID = "Div_Cabos_Rede";
testes.Attributes.Add("class", "col-md-12 letra");
testes.InnerHtml = "Cabos de rede";
TextBox Cabos_de_rede = new TextBox();
Cabos_de_rede.ID = "Txt_Cabos_Rede";
Cabos_de_rede.Attributes.Add("class", "col-md-12 form-control");
testes.InnerHtml = "Cabos de rede";
Body.Controls.Add(testes);
Body.Controls.Add(Cabos_de_rede);
This works fine almost fine (minor unrelated css problems), but when later I try to retrieve data from dynamically created textbox I get NULL value.
Here is my code to retrieve value:
TextBox testar = (TextBox)Body.FindControl("Txt_Cabos_Rede");
ScriptManager.RegisterStartupScript(this, GetType(), "alert", "alert('" + testar + "');", true);
The main problem dealing with dynamically created control is you need to reload them back in either Page Init or Page Load event.
FYI: We normally use either Panel or PlaceHolder to load controls instead of Body tag, so that we can style them easily.
ASPX
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="DemoWebForm.Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:PlaceHolder runat="server" ID="PlaceHolder1" />
<asp:Button runat="server" ID="SubmitButton" Text="Submit" OnClick="SubmitButton_Click" />
<br />
Posted Value:
<asp:Label runat="server" ID="ResultLabel" />
</form>
</body>
</html>
Code Behind
public partial class Default : System.Web.UI.Page
{
protected void Page_Init(object sender, EventArgs e)
{
HtmlGenericControl testes = new HtmlGenericControl("DIV");
testes.ID = "Div_Cabos_Rede";
testes.Attributes.Add("class", "col-md-12 letra");
testes.InnerHtml = "Cabos de rede";
TextBox Cabos_de_rede = new TextBox();
Cabos_de_rede.ID = "Txt_Cabos_Rede";
Cabos_de_rede.Attributes.Add("class", "col-md-12 form-control");
testes.InnerHtml = "Cabos de rede";
PlaceHolder1.Controls.Add(testes);
PlaceHolder1.Controls.Add(Cabos_de_rede);
}
protected void SubmitButton_Click(object sender, EventArgs e)
{
TextBox testar = FindControlRecursive(PlaceHolder1, "Txt_Cabos_Rede") as TextBox;
ResultLabel.Text = testar.Text;
}
// Custom method to search a control recursively
// in case it is nested inside other control.
// You can create it as an extension method if you would like.
public static 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);
}
}
I know you have a lot of questions. Before commenting on this question, please create a new project, and make this very simple code to work.
I made a simple control with 1 text box.
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="sTextBox.ascx.cs" Inherits="TestingASPNET.Controls.sTextBox" className="sTextBox"%>
<asp:Textbox runat="server" ID="tbNothing"/>
<br />
I call this control as a reference in my default.aspx Here's the simple code.
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="default.aspx.cs" Inherits="TestingASPNET._default" %>
<%# Reference Control="~/Controls/sTextBox.ascx"%>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:PlaceHolder runat="server" id="PlaceHolder1" />
</div>
</form>
</body>
</html>
In my code behind in default.aspx.cs I have.
protected void Page_Load(object sender, EventArgs e)
{
PlaceHolder1.Controls.Add(LoadControl("~/Controls/sTextBox.ascx"));
PlaceHolder1.Controls.Add(LoadControl("~/Controls/sTextBox.ascx"));
}
This adds the 2 sTextBox onto my page.
The problem I'm having is how to I use the control like I would a normal textBox. For example.
TextBox tb = new TextBox();
tb.Text = "textbox";
PlaceHolder1.Controls.Add(tb);
This adds a text box on the page with the text "textbox" in it.
Can Someone give me a way to do EXACTLY this, but with the control sTextBox.
you can get that behavior by adding properties to your custom control.
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var ctrl = (sTextBox) Page.LoadControl("~/sTextBox.ascx");
ctrl.Text = "something";
placeHolder1.Controls.Add(ctrl);
}
}
User Control :-
public partial class sTextBox : System.Web.UI.UserControl
{
public string Text { get; set; }
}
I couldn't get your code to work.
I either had to
var ctrl = (ProjectName.Controls.sTextBox) Page.LoadControl("~/Controls/sTextBox.ascx");
or import the control
using ProjectName.Controls;
When I did this, it worked.
Also your get set property wasn't work either, I had to change it to.
public string Text {
get
{
return tbNothing.Text;
}
set
{
tbNothing.Text = value;
}
}
Afterwards I added 1 more textbox into the control totaling 2. I changed the ID to tb1Text and tb2Text. I then had to get 2 methods for my get sets, which was
public string tb1Text {
get
{
return tb1.Text;
}
set
{
tb1.Text = value;
}
}
public string tb2Text
{
get
{
return tb2.Text;
}
set
{
tb2.Text = value;
}
}
inside my default code behind, I had to use
sTextBox ctrl = (sTextBox)Page.LoadControl("~/Controls/sTextBox.ascx");
ctrl.tb1Text = "something";
ctrl.tb2Text = "something 2";
PlaceHolder1.Controls.Add(ctrl);
This worked, now I know how to use 2 textboxes on 1 control :) . Hopefully it's the same with other controls that I have to make :S
I write one example to create own control on ASP.NET Froms. The controls very simple- combobox and button. User need choose value and when after he submit the button, the value from combobox need display in label.
So. Code of my Control:
public class MyControl:Control,IPostBackEventHandler
{
protected override void Render(HtmlTextWriter writer)
{
writer.AddAttribute("size","1");
writer.AddAttribute("ID","List2");
writer.AddAttribute("name", "ListYear");
writer.RenderBeginTag(HtmlTextWriterTag.Select);
for (int i = 1950; i < DateTime.Now.Year; i++)
{
writer.RenderBeginTag(HtmlTextWriterTag.Option);
writer.WriteEncodedText(i.ToString());
writer.RenderEndTag();
}
writer.RenderEndTag();
writer.AddAttribute("type","submit");
writer.AddAttribute("value","ClickMe");
writer.AddAttribute("name","BtnChange");
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
base.Render(writer);
}
public delegate void OnClickEventHandler(object sender, EventArgs args);
public event OnClickEventHandler Click;
public void RaisePostBackEvent(string eventArgument)
{
Click(this, new EventArgs());
}
}
The Page ASP:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="TestMyControl.aspx.cs" Inherits="Hello.TestMyControl" %>
<%# Register assembly="Hello" namespace="Hello" tagPrefix="MyContrl" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="Label1" runat="server" Text="Label" Visible="False"></asp:Label>
<br />
<MyContrl:MyControl runat="server" OnClick="Unnamed1_OnClick" ID="Control1"></MyContrl:MyControl>
</div>
</form>
</body>
</html>
And in the end Event function:
protected void Unnamed1_OnClick(object sender, EventArgs args)
{
Label1.Visible = true;
Label1.Text="You choose "+Control1.????+" year";
}
What substitute for a question mark that take the value from the list?
P.S. Something strange is going on. Because when I click the button, the handler is not called, and I can not get into Unnamed1_OnClick
Since you have set the value on an attribute, to retrieve it you need to access Attributes property
Make your control inherit from HtmlControl
public class MyControl : HtmlControl, IPostBackEventHandler
{
...
On your page
<MyContrl:MyControl runat="server" OnClick="Unnamed1_OnClick" ID="Control1"></MyContrl:MyControl>
On your code
Label1.Text = Control1.Attributes["value"];
You can debug this line to see all available attributes
You would need to pass the name of the combobox and its the value of the text that is selected.
Like this:
protected void Unnamed1_OnClick(object sender, EventArgs args)
{
Label1.Visible = true;
Label1.Text="You choose "+ myCustomControl.SelectedItem.Value.ToString()
+ " year";
}
(Sorry. I misread the initial post and edited my code accordingly once I realized my mistake.)
Add select list to your user control with name="YourSelectList"
then in the click event handler
protected void Unnamed1_OnClick(object sender, EventArgs args)
{
Label1.Visible = true;
Label1.Text="You choose "+Control1.YourSelectList.SelectedValue.ToString()+" year";
}
This question already has answers here:
Better way to find control in ASP.NET
(9 answers)
Closed 4 years ago.
I'm sorry, but I can't understand why this doesn't work. After compile, I receive a "Null reference exception". Please help.
public partial class labs_test : System.Web.UI.Page
{
protected void Button1_Click(object sender, EventArgs e)
{
if (TextBox1.Text != "")
{
Label Label1 = (Label)Master.FindControl("Label1");
Label1.Text = "<b>The text you entered was: " + TextBox1.Text + ".</b>";
}
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
Label Label1 = (Label)Master.FindControl("Label1");
Label1.Text = "<b>You chose <u>" + DropDownList1.SelectedValue + "</u> from the dropdown menu.</b>";
}
}
and UI:
<%# Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="test.aspx.cs" Inherits="labs_test" Title="Untitled Page" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
Type in text and then click button to display text in a Label that is in the MasterPage.<br />
This is done using FindControl.<br />
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Submit" /><br />
<br />
Choose an item from the below list and it will be displayed in the Label that is
in the MasterPage.<br />
This is done using FindControl.<br />
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged">
<asp:ListItem>Item 1</asp:ListItem>
<asp:ListItem>Item 2</asp:ListItem>
<asp:ListItem>Item 3</asp:ListItem>
</asp:DropDownList>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
</asp:Content>
Courtesy of Mr. Atwood himself, here's a recursive version of the method. I would also recommend testing for null on the control and I included how you can change the code to do that as well.
protected void Button1_Click(object sender, EventArgs e)
{
if (TextBox1.Text != "")
{
Label Label1 = FindControlRecursive(Page, "Label1") as Label;
if(Label1 != null)
Label1.Text = "<b>The text you entered was: " + TextBox1.Text + ".</b>";
}
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
Label Label1 = FindControlRecursive(Page, "Label1") as Label;
if (Label1 != null)
Label1.Text = "<b>You chose <u>" + DropDownList1.SelectedValue + "</u> from the dropdown menu.</b>";
}
private Control FindControlRecursive(Control root, string id)
{
if (root.ID == id) return root;
foreach (Control c in root.Controls)
{
Control t = FindControlRecursive(c, id);
if (t != null) return t;
}
return null;
}
When Label1 exists on the master page:
How about telling the content page where your master page is
<%# MasterType VirtualPath="~/MasterPages/PublicUI.Master" %>
Then making a method in the master like
public void SetMessage(string message)
{
Label1.Text = message;
}
And call it in page's code behind.
Master.SetMessage("<b>You chose <u>" + DropDownList1.SelectedValue + "</u> from the dropdown menu.</b>");
When Label1 exists on the content page
If it is simply on the same page, just call Label1.Text = someString;
or if you for some reason need to use FindControl, change your Master.FindControl to FindControl
FindControl only searches in the immediate children (technically to the next NamingContainer), not the entire control tree. Since Label1 is not an immediate child of Master, Master.FindControl won't locate it. Instead, you either need to do FindControl on the immediate parent control, or do a recursive control search:
private Control FindControlRecursive(Control ctrl, string id)
{
if(ctrl.ID == id)
{
return ctrl;
}
foreach (Control child in ctrl.Controls)
{
Control t = FindControlRecursive(child, id);
if (t != null)
{
return t;
}
}
return null;
}
(Note this is convenient as an extension method).