I am trying to add dynamically a user control I created to an aspx page after it is loaded.
I tried sending an ajax request to a handler that used RenderControl function and sent back the control's html. I appended it to the DOM using javascript.
The problem is that some of the controls must go through their Page_Load function and that doesn't happen when using RenderControl function.
Does anyone have any idea how can I do that?
try this:
System.Web.UI.Page page = new System.Web.UI.Page();
CustomUserControl userControl = page.LoadControl("~/control.ascx") as CustomUserControl;
if (userControl == null)
{
//error
}
userControl.ArticleId = id;
//call any other properties or methods you need
page.Controls.Add(userControl);
System.IO.StringWriter sw = new System.IO.StringWriter();
HttpContext.Current.Server.Execute(page, sw, false);
responseString = sw.ToString();
hope this will help!
Why dont you load and add the user control dynamically to the page?
I don't think you can do this that way.
Your controls don't go through their Page_Load, because they are not added to any control. All you are doing is rendering their html (using RenderControl) and loading it using javascript. There's no place for Page_Load event.
I would use UpdatePanel instead in that way:
<asp:UpdatePanel>
<ContentTemplate>
<asp:Panel ID="pnlDynamic" />
</ContentTemplate>
</asp:UpdatePanel>
and then in code behind add your dynamic controls to panel
pnlDynamic.Controls.Add(new YourControl());
Related
I am using a jQuery editor and when the user hits the submit button i put the content into asp.net Panel control as html and then when i render this Panel the html i added is not
retrieved.
function MoveData() {
var sHTML = $('#summernote_1').code();
// dvFrontPageHtml is asp.net Panel
$('[id*=dvFrontPageHtml]').html(sHTML);
setTimeout(function () {
javascript: __doPostBack('ctl00$ctl00$ContentPlaceHolderBody$ContentPlaceHolderBody$lnkSave', '');
}, 10000);
return false;
}
System.Text.StringBuilder sb = new System.Text.StringBuilder();
System.IO.StringWriter stWriter = new System.IO.StringWriter(sb);
System.Web.UI.HtmlTextWriter htmlWriter = new System.Web.UI.HtmlTextWriter(stWriter);
dvFrontPageHtml.RenderControl(htmlWriter);
string Message = sb.ToString();
The message does not returning the html added.
I dont want to use jQuery ajax call as of now.
Any suggestions
without seeing all the relevant code its hard to pinpoint the problem.
but im pretty sure you are trying to find an ASP.net control by its serverside ID from clientside.
dvFrontPageHtml is the Controls ID by which asp.net identifies it, and unless you explicitly tell ASP.Net otherwise, it will generate a different ID for the control to be used by scripts at clientside
you need to retrieve the panel's clientside ID thats being generated for it by asp.net
you do it by a preprocessor directive <%=dvFrontPageHtml.ClientID%>:
$('[id*=<%=dvFrontPageHtml.ClientID%>]').html(sHTML);
alternatively, if you want the clientside ID to be same as the serverside ID, you can set the control's attribute ClientIDMode="Static".
UPDATE:
from your comment it seems the problem is elsewhere. what comes to mind, is that RenderControl() takes the control as it was when sent to the client in the Response. but the control is not being submitted to the server in next Request, so you will not be able to retrieve its altered html.
what you can do as a workaround, is hook into ASP.NET's build in postback mechanism, and submit the panel's html as a custom event argument:
for the example, lets assume this is our html:
<asp:Panel ID="dvFrontPageHtml" runat="server" ClientIDMode="Static">test</asp:Panel>
<asp:Button ID="BT_Test" runat="server" Text="Button"></asp:Button>
this will be our javascript:
$(function(){
// add custom event handler for the submit button
$("#<%=BT_Test.ClientID%>").click(function (ev) {
//prevent the default behavior and stop it from submitting the form
ev.preventDefault();
//alter the panels html as you require
var sHTML = $('#summernote_1').code();
$('[id*=dvFrontPageHtml]').html(sHTML);
//cause a postback manually, with target = BTCLICK and argument = panel's html
__doPostBack('BTCLICK', $('[id*=dvFrontPageHtml]').outerHTML());
});
});
and here we capture the postback on serverside:
//we monitor page load
protected void Page_Load(object sender, EventArgs e)
{
string Message;
//check if its a postback
if (IsPostBack)
{
//monitor for our custom target "BTCLICK"
if (Request.Form["__EVENTTARGET"].CompareTo("BTCLICK") == 0)
{
// retrieve the panels html from the event argument
Message = Request.Form["__EVENTARGUMENT"];
}
}
}
Following is the scenario I am facing, I have a aspx page in which I have added my ascx user control, I also have a <a href control which call a js function to open a aspx popup.
when I open the popup, I need to send the data present in the ascx control to my popup. can you please guide me what method can I use to achieve this other than using session, as the data can be updated in many different places hence maintaining in session will be difficult.
Thanks
try with these syntaxe ( RegisterStartupScript + window.open)
ScriptManager.RegisterStartupScript(Page, Page.GetType(), "newWindow", "window.open('Test.aspx?ID=" + _cId + "','_blank','status=1,toolbar=0,menubar=0,location=1,scrollbars=1,resizable=1,width=30,height=30);", false);
You said that you are using a js function to open the aspx popup.
then it is simple.
1. Read the Data from the controls of the User control by using javascript
var variable1 = document.getElementByID("ControlId").value;
var variable2 = document.getElementByID("ControlId").value;
2. Pass this data as query string to the next page
window.open("http://www.w3schools.com?id=" + variable1 + "&name=" + variable2);
You can read this data from querystring from the next page
If you cant sent data as querystring , can try some other ways
1. Try to post the form to the other page using target="_blank".
we can dynamically change the form action if needed.
OR
2. Make use of the window.opener object from the popup to read the data from controls the opener page.
var variable1 = window.opener.getElementById("ControlId").value
Create a hidden variable in your ascx.
<asp:HiddenField runat="server" ID="hdnId" />
On page load of ascx set the value to be sent to the hidden variable
protected void Page_Load(object sender, EventArgs e){
hdnId.Value = <value to be sent to pop-up>;
}
Register a ajax manager in the code behind.
protected override void OnInit(EventArgs e)
{
RadAjaxManager.GetCurrent(this.Page).ClientEvents.OnRequestStart = "ajaxMngr_RequestStart;";
base.OnInit(e);
}
In the ajaxMngr_RequestStart() JS
function ajaxMngr_SA_RequestStart(sender, args) {
var oPatId = "<%=hdnSendPatId.Value %>";
//add code to open the pop-up, add oPatId as part of the URL
}
}
I use Telerik, which makes helps a lot in managing pop-ups. Let me know, if this helps.
Cheers!
MSDN says that create Dynamic Controls in PreInit Event of Page Life Cycle.
http://msdn.microsoft.com/en-us/library/ms178472.aspx
Why?
What advantage is derived by creating in PreInit Event?.
I have seen code where developers are creating dynamic controls in the Page_Load Method?
If there any difference?.
Regards
Page_Load works fine if you don't need to worry about saving the controls' ViewState across postbacks, but if you need to persist it, the Load stage is not where you should add these controls.
Dynamic controls must exist within the page's control hierarchy before the ViewState is loaded. There's only one stage before Load View State - Initialization. That means, if you want your dynamic controls to persist view state you must add them to the control hierarchy in the page's Init event.
https://web.archive.org/web/20210302172017/https://aspnet.4guysfromrolla.com/demos/printPage.aspx?path=/articles/092904-1.aspx
But mind that you cannot access the ViewState in Init event because it's yet not loaded. So you need to use a different persistence medium to store variables across postbacks(like Session) if required.
This reply might be late for the original poster but I thought it might help some other people.
If your application/ website doesn't use master page, it's best to create controls at Page_PreInit event. But if you use master page and want to create controls on content pages at run time Page_Init is the ideal event.
You can also create controls on Page_Load but bear in mind page load is fired after View State is loaded.
Tim,
Thanks for the reply.
I did a small experiment in which I am creating and adding a TextBox control dynamically in Page_Load method.
In the Postback click event of Button on the page,I am trying to get the value of the TextBox's Text Property.
I am able to get the value in the click event of the Button when the control is dynamically added in the Page_Load event and not the OnPreInt method.
I think that the Text value is retained in the ViewState even though the control is been added in Page_Load method.
following the code:
<div>
<p>
<asp:Label ID="lbl" runat="server" />
</p>
<p>
<asp:PlaceHolder ID="plcHolder" runat="server"></asp:PlaceHolder>
</p>
<p>
<asp:Button ID="btn" runat="server" Text="Click" OnClick="btn_Click" />
</p>
</div>
private void _createTextBox()
{
TextBox textBox = new TextBox();
textBox.ID = "txtBox";
textBox.Width = 250;
textBox.ReadOnly = false;
plcHolder.Controls.Add(textBox);
}
protected void Page_Load(object sender, EventArgs e)
{
_createTextBox();
if (!this.IsPostBack)
{
Control ctrl = plcHolder.FindControl("txtBox");
if (ctrl != null)
{
TextBox txtBox = ctrl as TextBox;
txtBox.Text = DateTime.Now.ToString();
}
}
}
protected void btn_Click(object sender, EventArgs e)
{
Control ctrl = plcHolder.FindControl("txtBox");
if (ctrl != null)
{
TextBox txtBox = ctrl as TextBox;
lbl.Text = txtBox.Text;
}
}
Kindly let me know is this correct or what am i doing wrong?
I'm trying to take an existing bunch of code that was previously on a full .aspx page, and do the same stuff in a .ashx handler.
The code created an HtmlTable object, added rows and cells to those rows, then added that html table the .aspx's controls collection, then added it to a div that was already on the page.
I am trying to keep the code in tact but instead of putting the control into a div, actually generate the html and I'll return that in a big chunk of text that can be called via AJAX client-side.
HtmlTable errors out when I try to use the InnerHtml property (says it isn't supported), and when I try RenderControl, after making first a TextWriter and next an HtmlTextWriter object, I get the error that Page cannot be null.
Has anyone done this before? Any suggestions?
*Most recent is above.
OK, even after Matt's update there is a workaround ;)
Firstly, we have to use a page with form inside. Otherwise we won't be able to add a ScriptManager control. One more thing: the ScriptManager control should be the first control in the form. Further is easier:
Page page = new Page();
Button button = new System.Web.UI.WebControls.Button
{
ID = "btnSumbit",
Text = "TextButton",
UseSubmitBehavior = true
};
HtmlForm form = new HtmlForm
{
ID="theForm"
};
ScriptManager scriptManager = new ScriptManager
{
ID = "ajaxScriptManager"
};
form.Controls.Add(scriptManager);
form.Controls.Add(button);
page.Controls.Add(form);
using (StringWriter output = new StringWriter())
{
HttpContext.Current.Server.Execute(page, output, false);
context.Response.ContentType = "text/plain";
context.Response.Write(output.ToString());
}
This works. The output is quite large so I decided not to include it into my answer :)
Actually, there is a workaround. Yep, we may render a control in handler.
Firstly, we need a formless page. Because without it we get:
Control 'btnSumbit' of type 'Button'
must be placed inside a form tag with
runat=server.
public class FormlessPage : Page
{
public override void VerifyRenderingInServerForm(Control control)
{
}
}
Secondly, nobody can prevent us from creating an instance of our FormlessPage page. And now let's add a control there (I decided to add a Button control as an example, but you could use any).
FormlessPage page = new FormlessPage();
Button button = new System.Web.UI.WebControls.Button
{
ID = "btnSumbit",
Text = "TextButton",
UseSubmitBehavior = true
};
page.Controls.Add(button);
Thirdly, let's capture the output. For this we use HttpServerUtility.Execute method:
Executes the handler for the specified
virtual path in the context of the
current request. A
System.IO.TextWriter captures output
from the executed handler and a
Boolean parameter specifies whether to
clear the
System.Web.HttpRequest.QueryString and
System.Web.HttpRequest.Form
collections.
Here is the code:
using (StringWriter output = new StringWriter())
{
HttpContext.Current.Server.Execute(page, output, false);
context.Response.ContentType = "text/plain";
context.Response.Write(output.ToString());
}
The result will be:
<input type="submit" name="btnSumbit" value="TextButton" id="btnSumbit" />
In addition I can recommend ScottGu's article Tip/Trick: Cool UI Templating Technique to use with ASP.NET AJAX for non-UpdatePanel scenarios. Hope, you could find a lot of useful there.
Another option is to host the ASP.NET HTTP pipeline in your process, render the page to a stream and read the HTML you need to send from the HttpListenerContext.Response.OutputStream stream after the page has been processed.
This article has details: http://msdn.microsoft.com/en-us/magazine/cc163879.aspx
I am generating a dropdown list in codebehind and cannot get the selectedindexchanged event to fire automatically. It works fine when put directly into the ASPX page, but I need it to be in the codebehind.
This doesn't work:
var deptList = new DropDownList
{
ID = "deptList",
DataSource = departments,
DataTextField = "deptname",
DataValueField = "deptid",
AutoPostBack = true,
EnableViewState = true
};
deptList.SelectedIndexChanged += new EventHandler(deptList_SelectedIndexChanged);
deptList.DataSource = departments;
deptList.DataTextField = "deptname";
deptList.DataValueField = "deptid";
if (!IsPostBack)
deptList.DataBind();
deptList.Items.Insert(0, new ListItem("---Select Department---", string.Empty));
writer.Write("Select a department: ");
deptList.RenderControl(writer);
but this works:
<asp:DropDownList ID="deptList" AutoPostBack="true" runat="server" OnSelectedIndexChanged="deptList_SelectedIndexChanged"></asp:DropDownList>
The problem may be if you are not adding the control to the page early enough. Controls need to be added early in the page lifecycle to get their events tied in.
You're probably doing it in the Load event, which is too late. Try adding it during the Init event or overriding the CreateChildControls method.
Edit: As Dave Swersky mentioned, make sure you do this on EVERY page request including postbacks.
You have a mesh in your code. Try to devide creating, data binding and events calling.
Example:
<asp:DropDownList ID="deptList" AutoPostBack="true" runat="server"></asp:DropDownList>
Then in code behind (Page_Load):
deptList.SelectedIndexChanged += new EventHandler(deptList_SelectedIndexChanged);
if (!IsPostBack)
{
deptList.DataTextField = "deptname";
deptList.DataValueField = "deptid";
deptList.DataSource = departments;
deptList.DataBind();
deptList.Items.Insert(0, new ListItem("---Select Department---", string.Empty));
}
To elaborate on Mike Mooney's answer: you also need to make sure you add the control back into the control tree on every postback. The control tree is recreated on each postback, read in from the markup. If you add it once programmatically and never again, there is no control in the tree to receive the event.
It appears that you are not adding the control to the controls collection. You must add the control somewhere in the control hierarchy and ensure it gets added on every postback to ensure the control exists to receive the event. By adding the control you shouldn't need to call RenderControl directly.
The problem i had was that if the drop down list didn't have AutoPostBack = true then it would never call the function.