On which Page life cycle are the Client IDs generated? - c#

i am programatically adding Webcontrols in to a User Control i am also adding a javascript event passing the controlID as a parameter but the clientID is the one i assigned a it does not contain the one that asp.net generates
var txt = new TextBox();
txt.ID = "MyID"+Number;
chkBox.Attributes.Add("onClick", "EnableTxtBox('" +txt.ClientID + "');");
i can workAround this by adding the parent control ID
chkBox.Attributes.Add("onClick", "EnableTxtBox('" + this.ClientID+"_"+txt.ClientID + "');");
On which Page life cycle are the Client IDs generated?

You need to add the control to the control hierarchy before you add the attribute.
var txt = new TextBox();
txt.ID = "MyID"+Number;
Controls.Add ( txt );
chkBox.Attributes.Add("onClick", "EnableTxtBox('" +txt.ClientID + "');");
ControlCollection is no ordinary collection; it notifies the owner control when controls are added, and the control can take appropriate actions.

You should be able to add the attribute during OnPreRender(). INamingContainer is so painful sometimes...

Related

c# How to utilize Page_init, ViewState and Page_Load properly?

I have been working with Web Forms for a short while now and I have read most of what I have found about this on google. However, I am still unclear on how to work with this properly. I like the picture in this answer, but find it a bit too generic. I have not found one decent, concrete example on how to work with these events.
I am currently creating several controls dynamically in code behind in the Page_Load event:
foreach (Service service in Services)
{
// service div
HtmlGenericControl serviceDiv = new HtmlGenericControl("div");
serviceDiv.ID = service.ID;
serviceDiv.Style.Add(HtmlTextWriterStyle.TextAlign, "center");
outerDiv.Controls.Add(serviceDiv); //outerDiv exists in the aspx page
// service updatepanel
UpdatePanel uPanel = new UpdatePanel()
{
ID = service.ID + "_uPanel",
UpdateMode = UpdatePanelUpdateMode.Conditional
};
serviceDiv.Controls.Add(uPanel);
// status span
HtmlGenericControl statusSpan = new HtmlGenericControl("span");
statusSpan.ID = service.ID + "_statusSpan";
statusSpan.InnerHtml = service.Status;
uPanel.ContentTemplateContainer.Controls.Add(statusSpan);
// show specific content
if (service.Status.Equals(ServiceControllerStatus.Running.ToString()))
{
// status color
statusSpan.Attributes.Add("class", "status-run");
// stop button
HtmlButton stopButton = new HtmlButton();
stopButton.ID = service.ID + "_btnStop";
stopButton.InnerHtml = "<i class=\"fa fa-stop btn-red\"/></i>";
stopButton.Attributes.Add("type", "button");
stopButton.Attributes.Add("runat", "server");
stopButton.Attributes.Add("class", "btn btn-link btn-xs");
stopButton.Attributes.Add("title", "Stop");
stopButton.ServerClick += new EventHandler(BtnStop_Click);
ScriptManager.GetCurrent(this).RegisterAsyncPostBackControl(stopButton);
uPanel.ContentTemplateContainer.Controls.Add(stopButton);
// restart button
HtmlButton restartButton = new HtmlButton();
restartButton.ID = service.ID + "_btnRestart";
restartButton.InnerHtml = "<i class=\"fa fa-refresh btn-blue\"/></i>";
restartButton.Attributes.Add("type", "button");
restartButton.Attributes.Add("runat", "server");
restartButton.Attributes.Add("class", "btn btn-link btn-xs");
restartButton.Attributes.Add("title", "Restart");
restartButton.ServerClick += new EventHandler(BtnRestart_Click);
ScriptManager.GetCurrent(this).RegisterAsyncPostBackControl(restartButton);
uPanel.ContentTemplateContainer.Controls.Add(restartButton);
}
else
{
// status color
statusSpan.Attributes.Add("class", "status-stop");
// start button
HtmlButton startButton = new HtmlButton();
startButton.ID = service.ID + "_btnStart";
startButton.InnerHtml = "<i class=\"fa fa-play btn-green\"/></i>";
startButton.Attributes.Add("type", "button");
startButton.Attributes.Add("runat", "server");
startButton.Attributes.Add("class", "btn btn-link btn-xs");
startButton.Attributes.Add("title", "Start");
startButton.ServerClick += new EventHandler(BtnStart_Click);
ScriptManager.GetCurrent(this).RegisterAsyncPostBackControl(startButton);
uPanel.ContentTemplateContainer.Controls.Add(startButton);
}
// version span
HtmlGenericControl versionSpan = new HtmlGenericControl("span");
versionSpan.ID = service.ID + "_version";
versionSpan.InnerHtml = service.Version;
versionSpan.Attributes.Add("class", "version-text");
serviceDiv.Controls.Add(versionSpan);
What would I gain from creating these in Page_Init? If I create them in Page_Init, how do I access them in Page_Load? Private global lists of UpdatePanels and HtmlButtons feels so unclean.
I know that the ViewState loads between Page_Init and Page_Load, but what does that really mean? Since I don't do full postbacks, but instead use RegisterAsyncPostBackControl to only update the UpdatePanel's on postback, don't I need to re-populate in Page_Load?
If you don't need the ViewState, then you can also create the controls in Page_Load. The ViewState is used to store the values of the controls (which ones depends on the control) and to use them when the PostBack is sent to the server.
For instance, if you have a textbox, the PostBack contains the new value of the textbox and also the old value in the ViewState. The ASP.NET framework now compares those two and raises the TextChanged event if necessary. Without ViewState, this would not be possible.
The best advice you can give regarding dynamically created controls in ASP.NET WebForms is to avoid using them. They increase complexity very fast und are usually not necessary (even if it seems so at first).
In the majority of the cases, there is a much simpler approach, e.g. by using a Repeater. In your case, you have a list of services. You can bind this list to a Repeater and by that avoid to create the controls manually. See this link on how to use a Repeater.
Another upside of using a Repeater is that you can define the UI in the ASPX markup instead of in the code behind file. In your example, you change the UI based upon the status of the service. In this case, using the ItemDataBound-event of the Repeater might be a good option.

CMSEditableRegion inside a code loop

I am trying to add a cmseditableregion to my Kentico webpart that exists inside of tabbed content, now the amount of tabs are flexible so I would like to generate this dynamically. I have tried the method that follows (stringbuilder) but it just renders it as html and not as a control when passed to a literal.
for (int i = 1; i <= TabCount; i++)
{
sb.AppendLine("<li class=\"htab-list__item--fininfo active\">");
sb.AppendLine("<a href=\"#financial-result\" class=\"htab-list__link tab-link\">");
sb.AppendLine("<cms:CMSEditableRegion runat=\"server\" id=\"ttl" + i.ToString() + "\" RegionType=\"Textbox\" RegionTitle=\"" + i.ToString() + " Title\" />");
sb.AppendLine("</li>");
Is there a way to make the CMSEditableRegion be able to be set dynamically in the code so that when the loop builds the page code it will be in the right spot as a control and not just html.
The full code has more html and 3 editable regions per loop but it wont even work with just one.
Adding control dynamically is done as follows:
// Let's assume that 'plc' is a placeholder. But it can be any control.
plc.Controls.Add(new LiteralControl("<li class=\"htab-list__item--fininfo active\">"));
plc.Controls.Add(new LiteralControl("<a href=\"#financial-result\" class=\"htab-list__link tab-link\">"));
plc.Controls.Add(new CMSEditableRegion { ID = "someid", RegionType = CMSEditableRegionTypeEnum.TextBox, RegionTitle = "sometitle" });
plc.Controls.Add(new LiteralControl("</li>"));
Also check out MSDN.
I suggest you to create an ad hoc PageType (called DocumentType in Kentico 7) where you can put the HTML text needed. Then you can display it using a Repeater web part or a ASP.NET repeater if, like me, you prefer to work in code.

Creation of TextBox dynamicly cause to lose the "name" attribute

I have this code to add a new TextBox to my UserControl:
/// <summary>
/// Create a new TextBox
/// </summary>
/// <returns>a new TextBox with the right name attribute</returns>
private TextBox createTextBox()
{
TextBox textbox = new TextBox();
textbox.Attributes["name"] = name + "_" + (textBoxList.Count + 1);
textbox.ID = name + "_" + (textBoxList.Count + 1);
return textbox;
}
on the output HTML the "name" attribute of this TextBox is changed, and the UserControl name is added...
<input name="multipleTextBox$test_1" type="text" id="multipleTextBox_test_1">
how can i avoid the "multiplartTextBox$" part of the name to be added ? it's important since i need my unique name to be right...
Set the TextBox.ClientIDMode to Static.
TextBox textbox = new TextBox();
textbox.ClientIDMode = ClientIDMode.Static;
ClientIDMode in ASP.NET 4.0
by default you cant. this is how ASP.NET and control name generation works especially if you are adding it in a user control. this is how ASP.NET differentiates with controls and naming conflicts on the client side. This is quite normal. why would it matter to you though you? why do you need access to the element at runtime? if you need access to it, simply user document.getElementById('multipleTextBox$test_xxx') :)
you can set the ClientIDMode to static though however I would advise against this unless you have good reason to do so - this would be the ID, and not the name
you can always access your control by ClientId property to get rendered Control ID and UniqueId to get rendered Control Name.

creating RadEditor dynamically asp.net

I want to add RadEditor dynamically. It is getting added to the page but as soon as postback occurs i get Multiple controls with the same ID 'EditorRibbonBarResourcesHolder' were found. Below is the code that i am using to add control dynamically.
RadEditor editor = new RadEditor();
editor.ID = "editor_" + itemTypeattribute.ItemAttributeID + rand.Next();
cellAttributeValue.Controls.Add(editor);
editor.DialogOpener.ID = "editor_dialopOpener_" + itemTypeattribute.ItemAttributeID;
editor.DialogOpener.Window.ID = "editor_dialopOpener_window_"+ ItemTypeattribute.ItemAttributeID;
editor.ClientIDMode = ClientIDMode.AutoID;
editor.EnableEmbeddedScripts = true;
editor.Height = 200;
Any help is appreciated. Thanks
Whenever I need to use a radeditor "dynamically" I have it on the page from the start with visible=false and then show it when I need it.

C# dynamically created control issue

i'm having issues retreiving the values out of a dynamically created dropdownlist. all controls are created in the Page_Init section. the listitems are added at that time as well from an array of listitems. (the controls are named the same so should be accessable to the viewstate for appropriate setting.)
here is the function that attempts to retrieve the values:
protected void Eng98AssignmentComplete_Click(object sender, EventArgs e)
{
String myID = "0";
Page page = Page;
Control postbackControlInstance = null;
// handle the Button control postbacks
for (int i = 0; i < page.Request.Form.Keys.Count; i++)
{
postbackControlInstance = page.FindControl(page.Request.Form.Keys[i]);
//Response.Write(page.Request.Form.Keys[i].ToString());
if (postbackControlInstance is System.Web.UI.WebControls.Button)
{
myID = Convert.ToString(
postbackControlInstance.ID.Replace("button_", ""));
}
}
String txtholder = "ctl00$ContentPlaceHolder$Eng098Instructors_" + myID;
Response.Write("MYID: " + myID + "<br/>");
DropDownList ddInstructorCheck = (DropDownList)Page.FindControl(txtholder);
Response.Write("Instructor Selected: "
+ ddInstructorCheck.SelectedValue + "<br/>");
}
here is the output I get, no matter which instructor was selected.....
MYID: 1_1
Instructor Selected: 0
ctl00$ContentPlaceHolder$Eng098Instructors_1_1
the name of the control is correct (verified via view source)....
ideas?
You're going to a lot of work to build this fancy string:
ctl00$ContentPlaceHolder$Eng098Instructors_1_1
That is the client ID of your control, not the server id. This code is running on the server side, and so you need the server id. To get that control using the server id, you need to do this:
ContentPlaceHolder.FindControl("Eng08Instructors_1_1");
Notice I didn't look in the page, because your content place holder created a new naming container.
Also, the way your loop is set up the myID variable will always end up holding the last button in the Keys collection. Why even bother with the loop?
Based on your comments, a better way to find the id of the dropdownlist is like this:
string id = ((Control)sender).ID.Replace("button_", "Eng098Instructors_");
why not just save the control in an instance in your class so that you don't have to use FindControl?
Do you also re-create the controls during the postback? Dynamically generated/added controls must be re-created with every request, they are not automatically re-created.
Why don't you cast the sender? This should be the button that caused the postback:
string myId = "0";
Button btn = sender as Button;
if (btn != null)
myId = btn.ID
...
You need to perform something like this because the UniqueID property is the key in Request.Form.
List<Button> buttons = new List<Button>();
List<DropDownList> dropdowns = new List<DropDownList>();
foreach (Control c in Controls)
{
Button b = (c as Button);
if (b != null)
{
buttons.Add(b);
}
DropDownList d = (c as DropDownList);
if (d != null)
{
dropdowns.Add(d);
}
}
foreach (String key in Request.Form.Keys)
{
foreach (Button b in buttons)
{
if (b.UniqueID == key)
{
String id = b.ID.Replace("button_", "");
String unique_id = "ctl00$ContentPlaceHolder$Eng098Instructors_" + id;
Response.Write("MYID: " + id + "<br/>");
foreach (DropDownList d in dropdowns)
{
if (d.UniqueID == unique_id)
{
Response.Write("Instructor Selected: " + d.SelectedValue + "<br/>");
break;
}
}
}
}
}
I'm not sure why you are generating the control in code (you can still add items dynamically if you do), but the code that generates the controls would probably be a huge help here. I'm guessing you are not setting the list item value, and instead just setting the list item text. Try seeing what you get from the SelectedText field and post your control creation function.
EDIT:
In response to your comment on #Martin's post, you said "yes I recreate the controls in the Page_Init function each time the page is created (initial or postback)". Are you also setting the selected value when you create them?
You can also use controls on the page even if your data comes from a database, the controls themselves don't have to be dynamically generated.
How about this?
((Button)sender).Parent.FindControl(myid)
Edit:I misunderstood your question. But i think you should follow page lifecycle. it is common issue for dynamically created controls.
I did some research and here is some info about Dynamically Created Controls may help you...
I had 2 catches.... here's what they were.
1. I didn't clear the table I was adding to before re-creating the controls.
apparently my attention to detail was off yesterday, i'm pretty sure the ctlXX frontrunner of the control was some different number upon postback due to how I was recreating the controls.
2. I was assigning the same list to all the dropdownlist controls.
once I called the lookup upon each creation a dropdownlist control, all works well.
anyway for what it's worth....

Categories

Resources