In this post I wanted to figure out how to create dynamically created textboxes in C# Visual Studio.
Adding additional textboxes to aspx based on xml
However, when I try to call the ID of these dynamically created textboxes later in my code to figure out what text the user entered into them, I am getting an error that says these IDs do not exist in the current context. Does anyone know how I would be able to call these?
credit to Adding additional textboxes to aspx based on xml
Here is my entire code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml.Linq;
namespace WebApplication4
{
public partial class WebForm15 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsCallback)
{
//credit to https://stackoverflow.com/questions/44076955/adding-additional-textboxes-to-aspx-based-on-xml#comment75336978_44078684
const string xml = #"<Number>
<Num>1</Num>
<Num>2</Num>
<Num>3</Num>
</Number>";
XDocument doc = XDocument.Parse(xml);
int i = 0;
foreach (XElement num in doc.Root.Elements())
{
TextBox box = new TextBox
{
ID = "dynamicTextBox" + i,
Text = num.Value,
ReadOnly = false
};
divToAddTo.Controls.Add(box);
divToAddTo.Controls.Add(new LiteralControl("<br/>"));
i++;
}
}
}
protected void BtnGetValues_Click(object sender, EventArgs e)
{
IList<string> valueReturnArray = new List<string>();
foreach (Control d in divToAddTo.Controls)
{
if (d is TextBox)
{
valueReturnArray.Add(((TextBox)d).Text);
}
}
//valueReturnArray will now contain the values of all the textboxes
}
}
}
Here is aspx:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm15.aspx.cs" Inherits="WebApplication4.WebForm15" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
</head>
<body>
<form id="form1" runat="server">
<div id="divToAddTo" runat="server" />
<asp:Button runat="server" ID="BtnGetValues" Text="GetValues" OnClick="BtnGetValues_Click" />
</form>
</body>
</html>
Figured it out!!! Here is what I found after scouring the internet for hours
Solution:
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!!!
Related
Please consider the following:
code behind:
public void InitiateTable()
{
Controls.Add(new LiteralControl("<table class=\"table table-invoice\" >")); //Line that gave me error
...
Controls.Add(new LiteralControl("</table>"));
}
on my ASP.Net page:
<% InitiateTable(); %>
When I run the code, it gives me an error saying:
The Controls collection cannot be modified because the control contains code blocks (i.e. <% ... %>).
Can someone please explain what I have done wrong?
Thank you.
Note Changed LiteralControl to Control as suggested in comment.
You cannot modify the controls collection where the container contains <% %> code blocks as the error message tells you. Controls.Add will modify the controls collection. To get around this:
In your aspx page change
<% InitiateTable(); %>
to
<asp:Literal runat="server" id="mytable" />
then in your page load method, add a call to InitiateTable()
then in your InitiateTable() method change your code to something like this:
public void InitiateTable()
{
var literalControlValue = new StringBuilder();
literalControlValue.Append("<table class=\"table table-invoice\" >");
...
literalControlValue.Append("</thead>"));
mytable.Text = literalControlValue.ToString();
}
Controls.Add(new LiteralControl("<table class='table table-invoice'>"));
The issue is when you use Controls you are referencing the Page itself rather than the area you call InitiateTable.
If you're inserting controls into this area, this is what a Placeholder is for:
<asp:Placeholder id="phTable"></Placeholder>
Then in your Page_Load or some other event code:
private void Page_Load(object sender, System.EventArgs e)
{
phTable.Controls.Add(new LiteralControl("<table class=\"table table-invoice\" >"));
phTable.Add(new LiteralControl("</thead>"));
}
The following code creates file.aspx and file.aspx.cs:
protected void Button1_Click(object sender, EventArgs e)
{
string fielName = Server.MapPath("~/file.aspx");
TextWriter tw = new StreamWriter(fielName);
tw.WriteLine(#"<%# Page Language=""C#"" AutoEventWireup=""true"" CodeFile=""file.aspx.cs"" Inherits=""file"" %>
<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"">
<html xmlns=""http://www.w3.org/1999/xhtml"">
<head runat=""server"">
<title></title>
</head>
<body>
<form id=""form1"" runat=""server"">
<div>
</div>
</form>
</body>
</html>
");
tw.Close();
tw = new StreamWriter(fielName + ".cs");
tw.WriteLine(#"using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
public partial class file : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(""new File "");
}
}
");
tw.Close();
}
I want to make the page name written in my Textbox.
I have tried putting textbox in html source of above code, but I'm getting an error.
CodeFile="""+TextBox1.Text+""" Inherits="""+TextBox1.Text+"""
You would be much farther ahead to work the way ASP.NET "thinks" about the page. I once worked on a very large, dynamic questionnaire. All of the controls were generated dynamically along with validations and everything else. At it's core, the way we did it was:
place a panel on the page
add controls to the panel
the code very roughly would look something like this:
var btn = new Button();
btn.ID = "theId";
btn.Text = "hi";
pnlDynamic.Controls.Add(btn);
Because you're dealing with dynamic controls, you might also want to make sure that you understand the page life-cycle...: http://msdn.microsoft.com/en-us/library/ms178472(v=vs.100).aspx
Make sure your web project is declared as a web site rather than a web application.
A web site is willing to dynamically compile each page on demand, unlike a web application, so something like this is in principle doable. If you really want to do it.
I have an aspx master/content page scenario. The parent page has an IFrame which points to a child.aspx. The child.aspx has a checkbox, On page_load of child.aspx, I want to show/hide the checkbox depending on the following logic:
- if the child.aspx is opened directly, then I have to show the checkbox.
- if the child.aspx is opened in the IFrame, then I have to hide the checkbox.
Basically, I want to check in child.aspx, if it contains a parent window then hide the checkbox control otherwise show it.
I will prefer the show/hide code in codebehind in Page_load event as I have to execute some more logic depending on whether the it is opened from parent window or not.
Till now I did the following:
In child.aspx
<asp:Content ID="Content1" ContentPlaceHolderID="Main" Runat="Server">
<script language="javascript" type="text/javascript">
function DoesParentExists()
{
var bool = (parent.location == window.location)? false : true;
var HClientID ='<%=hfDoesParentExist.ClientID%>';
document.getElementById(HClientID).Value = bool;
}
</script>
<div>
<h2>Content - In IFrame</h2>
<asp:HiddenField runat="server" id="hfDoesParentExist" />
<asp:CheckBox ID="chkValid" runat="server" />
<asp:ImageButton ID="ImageButton_FillW8Online" ImageUrl="~/images/expand.gif"
OnClick="btnVerify_Click" runat="server" style="height: 11px" />
</div>
</asp:Content>
in client.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "DoesParentExists", "DoesParentExists()", true);
if (hfDoesParentExist.Value == "true")
{
chkValid.Visible = false;
}
}
Using RegisterClientScriptBlock, I get error in JS. That the object hfDoesParentExist doesn't exist 'coz the control is not yet created. Right? I tried using RegisterStartupScript but in codebehind I always get null in hidden variable. I don't want to use the on button click or something like it. I need it on page_load event only. How to resolve the issue?
This line:
document.getElementById(HClientID).Value = bool;
Should be: (lower case value)
document.getElementById(HClientID).value = bool;
Also you cannot check the value of a hidden field set by javascript register callback, in the current executing context on the server side.
I would move the logic to the client side to hide or show the checkbox. If the field must indeed be removed from the page you can do that as well with javascript.
function DoesParentExists()
{
var bool = (parent.location == window.location)? false : true;
var cehckboxId ='<%=chkValid.ClientID%>';
if(bool){
document.getElementById(cehckboxId).style.display = 'none';
}
else {
document.getElementById(cehckboxId).style.display = 'block';
}
}
You may want to wrap the checkbox with a div and hide the container also to include the label.
To do it server-side, I would rely on a querystring parameter. Have the parent page load the child page by appending ?inframe=1. Then check for that value in your Page_Load.
OK, so I'm tyring to work with some simple stuff in ASP.NET and C# to get the hang of the super super basics, and I'm having trouble finding out how I can get this scope issue to work. At least, I think it's a scope issue! :)
So, here is my Default.aspx presentation markup:
<%# Page Language="C#" Inherits="project1.Tree" %>
<!DOCTYPE html>
<html>
<head runat="server">
<title>project1_test</title>
</head>
<body>
<form runat="server">
<p><asp:label runat="server" id="lblOutput" /></p>
<asp:TextBox ID="txtGrowBy" runat="server" />
<asp:Button id="btnGrow" runat="server" Text="Grow!!!" />
</form>
</body>
</html>
And here is my CodeBehind file:
using System;
using System.Web;
using System.Web.UI;
namespace project1
{
public partial class Tree : System.Web.UI.Page
{
public int height = 0;
public void Grow(int heightToGrow) {
height += heightToGrow;
}
protected void Page_Load(Object Source, EventArgs E)
{
Tree tree1 = new Tree();
string msg = "Let's plant a tree!<br/>";
msg += "I've created a tree with a height of " +
tree1.height + " metres.<br/>";
lblOutput.Text = msg;
}
public virtual void btnGrowClicked (object sender, EventArgs args)
{
txtGrowBy.Text = tree1.heightToGrow;
}
}
}
Now, I believe the issue lies with the fact that I'm not using a getter and sender, but I'm not 100% sure.
I take it you're variable height is not being maintained between postbacks?
This is because the web is stateless. Your variables are not maintained between postbacks unless you store the values in Session, ViewState or Hidden Fields. So you could do the following to maintain your height value between PostBacks:
ASPX:
<form runat="server">
<asp:HiddenField id="hd_Height" runat="server" />
</form>
Code Behind:
public int Height
{
get
{
return int.Parse(hd_Height.Value).ToString();
}
set
{
hd_Height.Value = value.ToString();
}
}
There's several immediate problems with your code; in the Page_Load method, you're creating a new Tree instance - you don't have to do this, as one was automatically created by IIS when the ASP.NET page was accessed. Use the this keyword in the Page_Load method to get access to that instance.
Further, nothing ever seems to call the Grow method; is this intentional? Shouldn't you be calling that from within the btnGrowClicked method?
And finally as GenericTypeTea points out, your height field won't be maintained between Postbacks. Easiest way to do this is with session state, eg:
private void PersistHeight(int height)
{
this.Session["height"] = height;
}
private int RestoreHeight()
{
return (int)this.Session["height"];
}
You could use viewstate as well (if Mono supports it); simply add the updated value to viewstate before giving control back to the browser. Then read from viewstate the original value saved in the last postback and incrementing the new value to it:
public int MyValue
{
get {return Convert.ToInt32(viewstate["myVal"]);}
set {viewstate["myVal"] = value;}
}
I hope that makes sense.
Trying to set the value of a literal user control on my child master page via the code behind of the same master page.
Here is example of the code I am using:
Global.master
<form id="form1" runat="server">
<div>
<asp:ContentPlaceHolder id="GlobalContentPlaceHolderBody" runat="server">
</asp:ContentPlaceHolder>
</div>
</form>
Template.master (child of Global.master)
<asp:Content ID="TemplateContentBody" ContentPlaceHolderID="GlobalContentPlaceHolderBody" Runat="Server">
<asp:Literal ID="MyLiteral1" runat="Server"></asp:Literal>
<p>This is template sample content!</p>
<asp:ContentPlaceHolder ID="TemplateContentPlaceHolderBody" runat="server">
</asp:ContentPlaceHolder>
Template.master.cs
protected void Page_Load(object sender, EventArgs e)
{
MyLiteral1.Text = "Test";
}
ContentPage.aspx
< asp:Content ID="ContentBody" ContentPlaceHolderID="TemplateContentPlaceHolderBody" Runat="Server">
</asp:Content>
Once I am able to achieve this, I will also need to be able to access content on the global and template master pages via content pages.
If I understand your scenario you want to have your content pages access items from your master pages. If so, you'll need to setup a property to expose them from your master page, and in your content page you can setup a MasterType directive.
Take a look at this post for an example.
Found a working solution. In the template.master (nested child master), I had to put the code in OnLoad event.
protected override void OnLoad(EventArgs e)
{
MyLiteral1.Text= "<p>MyLiteral1 Successfully updated from nested template!</p>";
base.OnLoad(e);
}
Very strange...
Basically, I am using the global master as the page that has code shared on every page, then I will have various nested pages to suit each website section. For the navigation nested template, I want to be able to show if the user is logged in and how many items in shopping cart.
If there is a better way to achieve this, I am open to suggestions.
EDIT: This is my answer when I thought you were trying to access a control on the child master from the parent master code behind.
You can use a recursive findControl function:
protected Control FindControlRecursive(string id, Control parent)
{
// If parent is the control we're looking for, return it
if (string.Compare(parent.ID, id, true) == 0)
return parent;
// Search through children
foreach (Control child in parent.Controls)
{
Control match = FindControlRecursive(id, child);
if (match != null)
return match;
}
// If we reach here then no control with id was found
return null;
}
Then use this code in your master page:
protected void Page_Load(object sender, EventArgs e)
{
//EDIT: if GlobalContentPlaceHolderBody isn't visible here, use this instead:
//Control c = FindControlRecursive("MyLiteral1", Page.FindControl("GlobalContentPlaceHolderBody"));
Control c = FindControlRecursive("MyLiteral1", GlobalContentPlaceHolderBody);
if(c != null)
((Literal)c).Text = "Test";
}