Wrox Programmer Forums
Go Back   Wrox Programmer Forums > ASP.NET and ASP > ASP.NET 2.0 > ASP.NET 2.0 Basics
|
ASP.NET 2.0 Basics If you are new to ASP or ASP.NET programming with version 2.0, this is the forum to begin asking questions. Please also see the Visual Web Developer 2005 forum.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the ASP.NET 2.0 Basics section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old April 3rd, 2007, 08:59 AM
Authorized User
 
Join Date: Dec 2006
Posts: 35
Thanks: 0
Thanked 0 Times in 0 Posts
Default Dynamically Added Control ID changes

Hi,

I've got an ascx file called UserControl.ascx with the following. Note the id is 'txtEmail' :

Code:
<asp:TextBox Columns="30" TabIndex="2" ID="txtEmail" runat="server" CausesValidation="True" CssClass="input" MaxLength="255" />

I add the control to a placeholder in my aspx.vb :

Code:
Dim myUserControl As UserControl = LoadControl("UserControl.ascx")
' Add the control to the place holder
Me.placeholder.Controls.Add(myUserControl)
Me.placeholder.Visible = True
The control is in a form which gets submitted.

When I check the Form values 'txtEmail' has no value because the id of the control was somehow changed to 'ctl07_txtEmail'.

What has happened? Do I now have to write additional code to find the txtEmail field within the posted form fields?

Thanks for any help.


http://www.thewebsiteshop.co.uk
__________________
http://www.thewebsiteshop.co.uk
 
Old April 3rd, 2007, 10:02 AM
Authorized User
 
Join Date: Dec 2006
Posts: 35
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Ok,

I seem to have got around this although I guess it's a hack.

The reason this happens is best described here: http://odetocode.com/Articles/450.aspx (Find "Name Mangling") - even though I'm not using Master pages here as the article describes.

I added the following to my aspx page:
Code:
<asp:HiddenField ID="hdnClientID" runat="server" />
Then changed my aspx.vb like so
Code:
' Add the control to the place holder
Me.phUserCreate.Controls.Add(myUserControl)
' Store the client id so that we can reference the controls after posting
Me.hdnClientID.Value = myUserControl.ClientID
' Show the placeholder
Me.phUserCreate.Visible = True
Now when I post the Form I append the client id to the original control id, a la:
Code:
If IsPostBack Then 
 Dim sClientID As String
 ' Retrieve the client id so that we can access form values
 sClientID = Request.Form("ClientID") & "$"
 myUser.Email = Request.Form(sClientID & "txtEmail")


http://www.thewebsiteshop.co.uk
 
Old April 3rd, 2007, 11:35 AM
planoie's Avatar
Friend of Wrox
 
Join Date: Aug 2003
Posts: 5,407
Thanks: 0
Thanked 16 Times in 16 Posts
Default

Why aren't you accessing the value of the textbox thru the textbox control??

The user control should have a member named "txtEmail" so you can code directly against that:

txtEmail.Text

You should *almost* never never never need to manually access the forms collection.


That fellow calling it "name mangling" I think is a little harsh. And it has nothing to do with Master pages. This behavior has been with .NET from the beginning for a good reason. The explanation is simple.

The textbox is a child control of your user control. The user control is a child control of a page. If there are 2 instances of the user control on a single page, there are also 2 textboxes. If the textbox was render with it's ID intact, you would have 2 "txtEmail" form elements which you can't do. So .NET prepends the parent (or "nameing container") to the ID. But all of this doesn't matter if you are access stuff from the server side code. However, if you want to touch the controls from the client side, then you need to take this into account. The simplest answer is to use the control's ".ClientID" property, which will give you the fully qualified client-side ID of the control. That you can use in JS to locate the element.

But this doesn't change the fact that you should not need any of this for your code. It should look like this:


If IsPostBack Then
 Dim sClientID As String
 ' Retrieve the client id so that we can access form values
 myUser.Email = txtEmail.Text

If you are trying to do this from the PAGE, you should create a public property on the user control that encapsulates the code that looks at the textbox:

Public ReadOnly Property Email As String
   Get
      Return txtEmail.Text
   End Get
End Property

-Peter
 
Old April 3rd, 2007, 02:28 PM
Authorized User
 
Join Date: Dec 2006
Posts: 35
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Peter,

Many Thanks for your reply.

I'm quite new to .NET but experienced with classic ASP. I definitely think I'm missing something here.

My understanding is that the textbox control simply generates the html input box that gets sent to the client. Yes, I can programmatically manipulate the control whilst on the server but once it has been sent to the client it is simply an html input tag in an html form.

I set my input tag up to have an id called 'txtEmail', yet when the html is generated .NET decides that I might not be capable of writing valid markup and so changes it for me ;)

The client doesn't send back a textbox control with a user input - it sends back the form element which (in classic ASP, at least I access through the Request.Form collection) and it is this element which I expect to be called 'txtEmail' that I am trying to get to.

I guess .NET probably does lots of clever stuff and keeps the textbox control and the input form element in sync using viewstate and this is probably where I have reached the limits of my understanding so far.

Anyway, if I try your suggestion I get the following error in the IDE:

Name 'txtEmail' is not declared

so I can't access it directly.

Kind Regards,

Paul

http://www.thewebsiteshop.co.uk
 
Old April 3rd, 2007, 02:36 PM
Friend of Wrox
 
Join Date: Jun 2003
Posts: 2,189
Thanks: 5
Thanked 59 Times in 57 Posts
Send a message via MSN to gbianchi
Default

hi there..

since you render the control at run time, the IDE doesn't know that it will exist when you run it...
so you have to do a findcontrol on your page, frame or placeholder, and that will return a handle to your textbox.

to findcontrol you pass the real id that you used, and .net will give you back the control that you want...

HTH

Gonzalo

================================================== =========
Read this if you want to know how to get a correct reply for your question:
http://www.catb.org/~esr/faqs/smart-questions.html
^^Took that from dparsons signature and he Took that from planoie's profile
================================================== =========
My programs achieved a new certification (can you say the same?):
WORKS ON MY MACHINE
http://www.codinghorror.com/blog/archives/000818.html
================================================== =========
 
Old April 3rd, 2007, 03:40 PM
Authorized User
 
Join Date: Dec 2006
Posts: 35
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Hi,

Gonzalo - thanks for the advice.

The HasControls() method on the placeholder returns false after posting the form.

First I tried this:

Dim txtEmail As TextBox = phUserCreate.FindControl("txtEmail")
myUser.Email = txtEmail.Text

and got this : Object reference not set to an instance of an object.

Then I tried invoking the HasControls method and got False.

Response.Write(phUserCreate.HasControls())
Response.End()

Kind Regards,

Paul



http://www.thewebsiteshop.co.uk
 
Old April 3rd, 2007, 03:52 PM
planoie's Avatar
Friend of Wrox
 
Join Date: Aug 2003
Posts: 5,407
Thanks: 0
Thanked 16 Times in 16 Posts
Default

First off, I forgot during the course of this discussion that you were adding the user control dynamically. So I haven't provided as good an answer as I could have. That's why you can't access that textbox by name.

Quote:
quote:
My understanding is that the textbox control simply generates the html input box that gets sent to the client. Yes, I can programmatically manipulate the control whilst on the server but once it has been sent to the client it is simply an html input tag in an html form.
Exactly.
Quote:
quote:
I set my input tag up to have an id called 'txtEmail', yet when the html is generated .NET decides that I might not be capable of writing valid markup and so changes it for me ;)
If you really feel that way. .NET renders ALL the controls, so don't feel bad. It's changing the ID sent to the client in order to maintain order among all the other controls, as I explained earlier.

Quote:
quote:
The client doesn't send back a textbox control with a user input - it sends back the form element which (in classic ASP, at least I access through the Request.Form collection) and it is this element which I expect to be called 'txtEmail' that I am trying to get to.
Yes, but this isn't classic ASP. If you are going to add user controls dynamically, you need to do so on both ends of a page interaction. If you add the control when the page initially loads, you should ALSO add the control in the say way when the page posts back. That way, you CAN access the controls child controls using pure server side code rather than relying on what you expect a form ID will be when it's posted. It doesn't take much to change the page's control tree and that will create a world of hurt for your app.

You'll need to maintain some information (possible in viewstate) that tells you what control(s) were added so you can re-add them to restore the control tree to the way it was when the page was first rendered. (I imagine this is what .NET does internally when you have complex data bound controls like lists or grids.)


-Peter
 
Old April 4th, 2007, 01:44 AM
Authorized User
 
Join Date: Dec 2006
Posts: 35
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Hi,

Thanks Peter. I tried your suggestion but still no luck.

Code:
If Page.IsPostBack Then
 ' Create an instance of the User Controls class
 Dim myUserControl As UserControl = LoadControl("UserControl.ascx")
 
 ' Add the control to the place holder
 Me.phUserCreate.Controls.Add(myUserControl)

 Dim txtEmail As TextBox = phUserCreate.FindControl("txtEmail")
 Response.Write(txtEmail.Text)
 Response.End()
resulted in

Code:
Object reference not set to an instance of an object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
Kind Regards,

Paul

http://www.thewebsiteshop.co.uk
 
Old April 4th, 2007, 04:13 AM
Authorized User
 
Join Date: Dec 2006
Posts: 35
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Ok guys,

I've made some progress.

First I moved the code that loads the control into the Page_Init event, as suggested in a number of other forum posts.

Then I used this neat little function I found at http://aspnet.4guysfromrolla.com/art...81402-1.2.aspx
Code:
lblText.Text += "[list]"
IterateThroughChildren(Me)
lblText.Text += "</ul>"

Private Sub IterateThroughChildren(ByVal parent As Control)

For Each c As Control In parent.Controls

    lblText.Text = lblText.Text & "<li>" & c.ToString & " - " & c.ID & "</li>" & vbCrLf
    If c.Controls.Count > 0 Then
        lblText.Text = lblText.Text & "[list]" & vbCrLf
        IterateThroughChildren(c)
        lblText.Text = lblText.Text & "</ul>" & vbCrLf
    End If
Next

End Sub
This displays all the controls within the page and I could see that txtEmail was indeed in there.

After some jiggery pokery, I managed to extract the value.
Code:
Dim txtEmail As TextBox = phUserCreate.Controls(0).Controls(7).FindControl("txtEmail")
lblText.Text = txtEmail.Text
So clearly .NET maintains the relationship between the control and the input tag that gets sent to and from the client and I hadn't yet crossed this leap of intuition.

Now I'm just wondering if there isn't some easier way to get to these values!

Thanks for the help folks, your guidance just helped me improve my understanding of .NET

Best Wishes,

Paul

http://www.thewebsiteshop.co.uk
 
Old April 4th, 2007, 07:27 AM
planoie's Avatar
Friend of Wrox
 
Join Date: Aug 2003
Posts: 5,407
Thanks: 0
Thanked 16 Times in 16 Posts
Default

Yes, this is a much easier way.

First, add a public property to your user control that exposes the text property of the email textbox:
Code:
Public ReadOnly Property Email As String
   Get
      Return txtEmail.Text
   End Get
End Property
Now you should be able to access that property directly off the user control:
(Note that I'm not sure what the type is of your user control. The file is "UserControl" so I'll assume the class type is also "UserControl", although this is not good practice as the class name "UserControl" is more than ambiguous. Just notice the conversion in the first line below, that's the key.)
Code:
Dim myUserControl As UserControl = CType(LoadControl("UserControl.ascx"), UserControl)
 
' Add the control to the place holder
Me.phUserCreate.Controls.Add(myUserControl)

Response.Write(myUserControl.Email) 'pulls the email textbox .Text value
Response.End()
-Peter





Similar Threads
Thread Thread Starter Forum Replies Last Post
Problem w/ dynamically added controls in GridView jpamental Pro Visual Basic 2005 2 May 12th, 2006 09:10 AM
Dynamically added panel with radio buttons ADM10 Visual Basic 2005 Basics 1 May 11th, 2006 10:27 PM
Capturing Dynamically Added Client Values Colonel Angus ASP.NET 1.0 and 1.1 Professional 4 April 14th, 2006 12:38 PM
Raise Event for Dynamically Added DropDownList DolphinBay ASP.NET 1.0 and 1.1 Professional 3 December 6th, 2005 02:22 PM
Control not added to code page shmacgregor VS.NET 2002/2003 2 March 26th, 2004 05:49 PM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.