Hi All - I have searched for and read about every post concerning using the AJAX library in an ASCX control and I am at a loss. I sure hope someone can help me figure out how to get it to work.
I am dynamically adding ASCX controls to my page using the Page.LoadControl method and it works fine. I have an Update Panel containing a TextBox control that I try to access from the ASPX page but it says it does not exist. I even have a property that specificallt returns the text box for me. When I Debug I look at the Update Panel and it is there with one control. That control is a Content Template and it has 0 controls. I don't know where my TextBox has gone. I wanted to get a handle on it so that I could add an event handler.
I have tried several other approaches inclusing dynamically adding the control to the update panel at run time and that failed miserably. Does anyone have any suggestions?
Any help is appreciated. Thanks!
DK
Try creating your dynamic controls in Page_Init event handler (same signature as Page_Load). Most problems like this have to do with the fact that code executed on postbacks, such as button click handler, is called before Page_Load, thus before your dynamic controls are recreated. Another good reason to have your controls created in Page_Init: only then they participate in ViewState restoration (as long as you assign them with the same ID in all the roundtrips).Thanks for the suggestion. I will give that a try and post back the results.
That did not work unfortunately. The TextBox is still not there when I try to add a Handler.
I did want to add some additional information that may or may not help. My TextBox controls on the ASPX page that are inside of Update Panels work perfectly so my web and everything else is configured properly. It is just the use in an ASCX control that is not working.
I have read many other posts in this newsgroup with the same issue but I am not seeing anyone posting a real resolution as far as I can tell. Does the AJAX team at MS have any perspecitve or guidance on this?
Thanks,
DK
Could you please submit a minimal code sample where the problem appears? I'd give it a try...
I am having the same problem, this is some sample code:
In the User Control ascx
<%@.ControlLanguage="VB"AutoEventWireup="false"Inherits="ucCalendarWithTextBox"Codebehind="ucCalendarWithTextBox.ascx.vb" %>
<%--Dynamic atlas updatepanel is possible as of June 2006, we still haven't download that yet--%>
<%@.RegisterAssembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
Namespace="System.Web.UI"TagPrefix="asp" %>
<
asp:UpdatePanelID="up2"runat="server"><Triggers><asp:AsyncPostBackTriggerControlID="CalendarPicker"EventName="SelectionChanged"/></Triggers><ContentTemplate><asp:TextBoxID="TxtDate"runat="server"Width="120"ReadOnly="false"AutoPostBack="true"></asp:TextBox></ContentTemplate></
asp:UpdatePanel>In an aspx page
Dim
calFromAs UcCalendarWithTextBox = Page.LoadControl("../UcCalendarWithTextBox.ascx")The problem is:
calFrom.TxtDate = Nothing. i.e. I can't find the controls in my contenttemplate
Sure - Here is the code for my ASX control:
-----------------------------
<%
@.ControlLanguage="vb"AutoEventWireup="false"CodeBehind="MCAProducerBasePercentControl.ascx.vb"Inherits="MCAWeb.MCAProducerBasePercentControl" %><
tableid="tblProducerBasePercent"runat="server"><tr><tdalign="left"style="width: 75px"><asp:UpdatePanelID="upProducerID"runat="server"><ContentTemplate><asp:TextBoxID="txtProducerID"runat="server"Width="75px"></asp:TextBox></td></ContentTemplate></asp:UpdatePanel></td><tdalign="left"style="width: 115px"><asp:TextBoxID="txtCommissioningID"runat="server"Width="115px"></asp:TextBox></td><tdalign="left"style="width: 75px"><asp:TextBoxID="txtAmount"runat="server"Width="75px"></asp:TextBox></td><tdalign="left"style="width: 75px"><asp:TextBoxID="txtRate"runat="server"Width="75px"></asp:TextBox></td><tdalign="left"style="width: 45px"><asp:ButtonID="btnAddOrDelete"runat="server"Text="Add"Width="45px"/></td></tr></
table>-----------------------------
In my code behind of the ASCX control, I have a property that returns the TextBox located inside of the UpdatePanel:
-----------------------------
Public
ReadOnlyProperty ProducerID()As TextBoxGetReturn txtProducerIDEndGetEndProperty-----------------------------
I then load the control at some point in my ASPX page:-----------------------------
producerControl = Page.LoadControl("~/MCAProducerBasePercentControl.ascx")-----------------------------
Then when I try to access the property and get the text box to add a handler dynamically it fails because it cannot see the Text Box:
-----------------------------
AddHandler
CType(producerControl, MCAProducerBasePercentControl).ProducerID.TextChanged,AddressOfMe.HandleExternalIDValidation-----------------------------
As an update, I decided to try creating the TextBox control on the fly in the ASPX page, adding the Event Handler and the adding it to the Controls collection of the ContentTemplateContainer object inside of the UpdatePanel. For example:
CType
(producerControl, MCAProducerBasePercentControl).ProducerIDUpdatePanel.ContentTemplateContainer.Controls.Add(txtTest)When the page is rendered the event still does not fire off however I am seeing that it appears to have registered all of the update panels, inlcuding the one contained in my dynamically added ASCX control (highligted below in bold): //<![CDATA[
Sys.WebForms.PageRequestManager._initialize('ScriptManager1', document.getElementById('frmMCADetail'));
Sys.WebForms.PageRequestManager.getInstance()._updateControls(['tUpdatePanel2','tUpdatePanel1','tctl06$upProducerID'], [], [], 90);
//]]>
However, I also notice that the above reference does not match the actual ID of the panel:
(NOTE: a 't' has been added to all of the UpdatePanel ID names in the above PageRequestManager. I am referring to the '$' versus the underscore character)
<div id="ctl06_upProducerID">
<input name="ctl06$txtTest" type="text" onchange="javascript:setTimeout('__doPostBack(\'ctl06$txtTest\',\'\')', 0)" onkeypress="if (WebForm_TextBoxKeyHandler(event) == false) return false;" id="ctl06_txtTest" />
</div>
In my other UpdatePanels, the ID matches and everything works great. Here is an example:
<div id="UpdatePanel1">
<input name="txtContractAccount" type="text" onchange="javascript:setTimeout('__doPostBack(\'txtContractAccount\',\'\')', 0)" onkeypress="if (WebForm_TextBoxKeyHandler(event) == false) return false;" id="txtContractAccount" style="width:100px;" />
</div>
Is this perhaps my problem at least in terms of this approach of adding the TextBox on the fly and the event not firing off?
Just a guess: maybe you both forget to add the dynamically created user control to some container on the page? Page.LoadControl only is not enough! I re-created the sample on my workstation (in C#), and it works fine, assuming it's done like this:
ASCX code:
<%@. Control Language="C#" AutoEventWireup="true" CodeFile="CalendarWithTextBox.ascx.cs" Inherits="CalendarWithTextBox" %>
<%@. Register Assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Namespace="System.Web.UI" TagPrefix="asp" %>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:TextBox ID="TxtDate" runat="server" Width="120px" ReadOnly="false" AutoPostBack="true"></asp:TextBox>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="TxtDate" />
</Triggers>
</asp:UpdatePanel>
Code-behind of user control:
public partial class CalendarWithTextBox : System.Web.UI.UserControl
{
public string Date
{
get
{
return TxtDate.Text;
}
set
{
TxtDate.Text = value;
}
}
}
and finally, the code-behind of the page
private CalendarWithTextBox Calendar;
protected void Page_Init(object sender, EventArgs e)
{
Calendar = Page.LoadControl("CalendarWithTextBox.ascx") as CalendarWithTextBox;
form1.Controls.Add(Calendar);
}
protected void Page_Load(object sender, EventArgs e)
{
Calendar.Date = String.Format("{0:dd.MM.yyyy}", DateTime.Now);
}
User control is loaded in Page_Init with purpose, as only then it properly participates in page viewstate, and your controls are ready when handling postback events (Page_Load happens after your button click handlers, for example!)
Good thinking but of course I have added the control to the Page. It shows up just fine once it is rendered. The control is just dead...I believe it is related though to both techniques I mention above in my previous posts. Not only can I not see the control to add an event handler, when I add a control on the fly and add to the UpdatePanel the ID's are mismatched anyway.
You seem to be really stuck on this idea of Page_Init which I kind of understand but 1) I have never had issues with just firing off my routines in the Page_Load event and things working fine and 2) this is not an issue related to loading the ASCX control. This is an issue with using the Ajax UpdatePanel in a user control.
So I will ask again, is there a member of the MS team that can say whether or not definitively if Ajax can be used with a user control loaded using ASCX and Page.LoadControl()?
Thanks!
DK
There is nothing that forbids using update panel combined with dynamically loaded controls. Done that many times. Not without problems, there is always something new to discover about AJAX, but it does work.
Nevertheless, I've committed a small sample in VB, looking like your scenario (user control with update panel, loaded dynamically, with control whose events handlers are provided by the containing page). Here it just works! I hope this will be helpful. For some reasons I can't submit attachments, so I provide complete code down here in the post. Create a new empty AJAX website (VB), then copy'n'pastedefault.aspx andmycontrol.ascx files listed below.
And indeed, preaching the use of Page_Init has become a kind of a personal obsession, after seeing so many people getting into trouble because of ignoring the page event sequence ...
MyControl.ascx
<%@. Control Language="VB" AutoEventWireup="false" CodeFile="MyControl.ascx.vb" Inherits="MyControl" %>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" ChildrenAsTriggers="true" UpdateMode="Always">
<ContentTemplate>
Type some text:<br />
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox><asp:Button ID="Button1" runat="server" Text="Ok" Width="65px" />
</ContentTemplate>
</asp:UpdatePanel>
MyControl.ascx.vb
Partial Class MyControl
Inherits System.Web.UI.UserControl
Public Property Text() As String
Get
Return TextBox1.Text
End Get
Set(ByVal value As String)
TextBox1.Text = value
End Set
End Property
Public ReadOnly Property OkButton() As Button
Get
Return Button1
End Get
End Property
End Class
Default.aspx
<%@. Page Language="VB" AutoEventWireup="true" CodeFile="Default.aspx.vb" Inherits="_Default" %>
<%@. Register src="http://pics.10026.com/?src=MyControl.ascx" TagName="MyControl" TagPrefix="uc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true" />
<asp:UpdatePanel ID="UpdatePanel" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:Panel ID="panelControls" runat="server">
</asp:Panel>
<asp:Panel ID="panelResult" runat="server">
<asp:Label ID="LabelResult" runat="server" Text="-"></asp:Label><br />
</asp:Panel>
</ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
</html>
Default.aspx.vb
Partial Class _Default
Inherits System.Web.UI.Page
Private control As MyControl
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
control = CType(Page.LoadControl("~/MyControl.ascx"), MyControl)
panelControls.Controls.Add(control)
AddHandler control.OkButton.Click, AddressOf Me.ButtonOk_Click
End Sub
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If (Not Page.IsPostBack) Then
control.Text = "Hello"
End If
End Sub
Protected Sub ButtonOk_Click(ByVal sender As Object, ByVal e As System.EventArgs)
LabelResult.Text = "You've entered: " & control.Text
UpdatePanel.Update()
End Sub
End Class
Thanks much for the sample. I will follow your advice and try your sample project to see if I can get the same results. Perhaps it will show me something obvious I am missing.
On the Page_Init thing, I understand your sentiment and very much appreciate your effort. I really appreciate the help you have given me thus far.
DK
Well I think I finally got it working properly. I think your solution offered me a couple of insights.
First, I did have to add the dynamically loaded control to a Controls collection of some control on the page before I could add a handler. Perhaps that is what you were saying earlier but I took your post that you were asking if I was adding the ASCX control to the page at all. Anyway, once I added it to the Table's Control collection on my Page, I was able to access the TextBox and add a handler.
Secondly, your example made me realize that I was not rendering the controls again on a post back. I am not sure how I missed that one ;-) I have a need for controls to be dynamically loaded both on a selection from a dropdown and when someone clicks an Add button. I will need to place that added data in session somewhere and then load it each time so that when the partial page postback occurs it will add the handler again and everything will be wired up since these controls are not statically added to the page at design time and I don't have anything in Viewstate for them (unless I am missing something?).
I also decide to follow your advice on using Page_Init and it has prompted me to revisit the page life cycle text again to make sure I am up to speed.
I don't know if this thread is finished and I am not sure which post to mark as having the answer. Thanks again for your help and I will post if I have any updates.
DK
Nice to hear that, I hope you will get the remaining issues solved too.
As for adding controls - it indeed needs to be added to the ASP.NET form control, or somewhere within it's scope. Same in design time - if you place a control outside of <form> tag, you will also get a nasty runtime error.
If you create the user control in Page_Init and assign it with an explicit and always the same server-side ID, you do not need to preserve the drop down list items in a session or stuff. Just add the new items to DropDownList.Items collection whenever you need it, and they will be preserved in the viewstate and assigned back to your dropdown on postbacks. It does not make a difference if you make a control dynamically or design time - as long as you do it in a right sequence, they all can make use of the view state.
It seems that we've exhausted the issue, so feel free to close the thread any time!
Hi guys,
Just wanted to add my issue and what I discovered I had to do.
I'm dynamically loading a bunch of ascx controls into tables that are created by ascx controls.
Pseudocode
for each ctl in list of control definitions loaded from an xml file (or database)
create an ascx ctl (that has an update panel in it) with loadcontrol (this could be a control which would cause this loop to be executed for the controls in that control basically a panel with panels in it)
set some values
add to this control's table control.
loop
on post back, I get an error of cannot find ctl named ddValue for displayPanel trigger.
I think the problem occurs because the top ascx control isn't added to the main Page controls until after all the sub controls are added and when it gets to the postback control, it's trying to add it to a control that hasn't been added to the page yet. weird thing is it doesn't cause any problem when it loads the first time it's only on postback.
I fixed it by assigning the trigger in the code for the ascx load event instead of declaratively on the ascx page.
No comments:
Post a Comment