Solved

ClientId for a control in a user control

Posted on 2006-06-20
15
1,050 Views
Last Modified: 2008-01-16
I am working on a tree view control for a project that I am currently involved in. This tree view is made of three parts: TreeNode class, TreeNodeCollection class, and TreeView user control. The control has one line of HTML, a div container. When I call a function, I need it to run through the tree node collection recursively and generate the links and buttons necessary. Ok, well I've got the code generating all of the links and buttons, but the actually hiding of the nodes isn't happening because the javascript requires the id of the containing div. I am coding it to take the ClientId of the div as I create it, but it is only giving me the id that fed to the control, and not the one used when the page is generated. This is doing some screwy stuff, so if you want to give me some pointers elsewhere, I'ld definitely appreciate it.

I'm not going to post all of the code, just what I find to be the problem areas.

TreeView.ascx html
<%@ Control Language="vb" AutoEventWireup="false" Codebehind="TreeView.ascx.vb" Inherits="PeCON.TreeView" TargetSchema="http://schemas.microsoft.com/intellisense/ie5" %>
<div id="TreeViewContainer" runat="server" style="text-align: left"></div>


TreeView.ascx.vb
    Public Sub BuildTreeView()
        ' call recursive method for displaying nodes

        'TreeViewContainer is defined in the Windows Generated Code section but is not instantiated when we come across this code
        If IsNothing(TreeViewContainer) Then
            TreeViewContainer = New Web.UI.HtmlControls.HtmlGenericControl("div")
            Me.Controls.Add(TreeViewContainer)
        End If

        DisplayNodes(_nodes, TreeViewContainer, 0)
    End Sub

    Private Sub DisplayNodes(ByVal Nodes As TreeNodeCollection, ByVal Container As Web.UI.Control, ByVal Level As Integer)
        For i As Integer = 0 To Nodes.Count - 1
            Dim hl As New Web.UI.WebControls.HyperLink
            hl.Text = Nodes(i).Name
            hl.NavigateUrl = Nodes(i).Url
            Container.Controls.Add(hl)

            Dim newLine As New Web.UI.WebControls.Literal
            newLine.Text = "<BR>"
            Container.Controls.Add(newLine)

            If Nodes(i).HasChildren Then
                Dim btn As New Web.UI.WebControls.Image
                btn.ID = "btn" & i.ToString & "_" & Level.ToString
                btn.ImageUrl = "..\images\plus.gif"
                Container.Controls.Add(btn)

                Dim newDiv As New Web.UI.HtmlControls.HtmlGenericControl("div")
                newDiv.ID = "div" & i.ToString & "_" & Level.ToString
                newDiv.Style.Add("text-align", "left")
                newDiv.Style.Add("margin-left", CStr(Level * 0.2) & "in")
                DisplayNodes(Nodes(i).Children, newDiv, Level + 1)
                Container.Controls.Add(newDiv)

                btn.Attributes.Add("onclick", "ToggleDisplay(this, " & newDiv.ClientID & ")")
            End If
        Next
    End Sub


Generated output:
<div id="mainContent_divContent" align="center" class="ContentPane">
      <img class="ContainerTopLeft" src="images\cont-tl.gif">
      <img class="ContainerTopRight" src="images\cont-tr.gif">
      <img class="ContainerBottomLeft" src="images\cont-bl.gif">
      <img class="ContainerBottomRight" src="images\cont-br.gif">
      <div>
            <a href="Design/eater.aspx">Databases</a><BR>
            <img id="mainContent_TreeView_btn0_0" onclick="ToggleDisplay(this, div0_0)" src="images/plus.gif" alt="" border="0" />
            <div id="mainContent_TreeView_div0_0" style="text-align:left;margin-left:0in;">
                  <a href="Design/someplace.aspx">PeCON</a><BR>
                  <img id="mainContent_TreeView_btn0_1" onclick="ToggleDisplay(this, div0_1)" src="images/plus.gif" alt="" border="0" />
                  <div id="mainContent_TreeView_div0_1" style="text-align:left;margin-left:0.2in;">
                        <a href="Design/blah.aspx">Stored Procedures</a><BR>
                        <a href="Design/blah.aspx">Tables</a><BR>
                        <a href="Design/blah.aspx">Views</a><BR>
                        <a href="Design/blah.aspx">User Defined Functions</a><BR>
                  </div>
            </div>
      </div>
</div>
0
Comment
Question by:fizch
  • 8
  • 5
15 Comments
 
LVL 4

Expert Comment

by:gregg1ep00
ID: 16946018
If you're instantiating the div from code, you need to set the "Id" property or else the tag will not get rendered with a client-side id.  Simply add the line:

TreeViewContainer.Id = "TreeViewContainer"

to your BuildTreeView() method like this:

Public Sub BuildTreeView()
        ' call recursive method for displaying nodes

        'TreeViewContainer is defined in the Windows Generated Code section but is not instantiated when we come across this code
        If IsNothing(TreeViewContainer) Then
            TreeViewContainer = New Web.UI.HtmlControls.HtmlGenericControl("div")
            TreeViewContainer.Id = "TreeViewContainer"
            Me.Controls.Add(TreeViewContainer)
        End If

        DisplayNodes(_nodes, TreeViewContainer, 0)
End Sub
0
 
LVL 6

Author Comment

by:fizch
ID: 16946241
Ok, that got me one step closer, but I still do not have the entire ClientId for the divs that I am trying to pass to the javascript.
0
 
LVL 4

Expert Comment

by:gregg1ep00
ID: 16946362
Ok, a few questions:
1) Which version of .NET are you using?
2) What page event are you launching your "BuildTreeView()" method from?
0
 
LVL 6

Author Comment

by:fizch
ID: 16946387
1) I am using 1.1
2) Page_Load of the main page
0
 
LVL 4

Expert Comment

by:gregg1ep00
ID: 16946536
Ok, try this...

Instead of using the <div id="TreeViewContainer"> in the html, can you try using an <asp:Panel> control?  I think what's happening is, because HtmlGenericControl does not implement INamingContainer, it's not rendering the ClientID properly.  Panel DOES, however, implement INamingContainer, so this may resolve your issue altogether.  The Panel control, IIRC, renders itself as a div.

You can also safely get rid of these lines in the "BuildTreeView()" method:

If IsNothing(TreeViewContainer) Then
            TreeViewContainer = New Web.UI.HtmlControls.HtmlGenericControl("div")
            Me.Controls.Add(TreeViewContainer)
End If


You may also want to try replacing all your HtmlGenericControls in code (i.e., newDiv in DisplayNodes() ) with Panel controls.
0
 
LVL 6

Author Comment

by:fizch
ID: 16946667
Ok, that didn't really help at all. I've got the same issue as before. The client id is still listing the information I fed it.
0
 
LVL 4

Expert Comment

by:gregg1ep00
ID: 16946700
Wow, ok.  I must be confusing myself now.  Sorry about that.  ;)

Can you give me an updated generated output?
Thx
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 6

Author Comment

by:fizch
ID: 16946798
Ok, you will notice that the image and the hyperlink have switched places. I've done a little rearranging to get the information setup properly.

<div id="mainContent_divContent" align="center" class="ContentPane">
      <img class="ContainerTopLeft" src="images\cont-tl.gif">
      <img class="ContainerTopRight" src="images\cont-tr.gif">
      <img class="ContainerBottomLeft" src="images\cont-bl.gif">
      <img class="ContainerBottomRight" src="images\cont-br.gif">
      <div id="mainContent_TreeView_TreeViewContainer">
            <img id="mainContent_TreeView_btn0_0" onclick="ToggleDisplay(this, div0_0)" src="images/plus.gif" alt="" border="0" />&nbsp;
            <a href="design/eater.aspx">Databases</a><BR>
            <div id="mainContent_TreeView_div0_0" style="text-align:left;margin-left:0.1in;">
                  <img id="mainContent_TreeView_btn0_1" onclick="ToggleDisplay(this, div0_1)" src="images/plus.gif" alt="" border="0" />&nbsp;
                  <a href="design/someplace.aspx">PeCON</a><BR>
                  <div id="mainContent_TreeView_div0_1" style="text-align:left;margin-left:0.2in;">
                        <a href="design/blah.aspx">Stored Procedures</a><BR>
                        <a href="design/blah.aspx">Tables</a><BR>
                        <a href="design/blah.aspx">Views</a><BR>
                        <a href="design/blah.aspx">User Defined Functions</a><BR>
                  </div>
            </div>
      </div>
</div>
0
 
LVL 4

Expert Comment

by:gregg1ep00
ID: 16946931
In your DisplayNodes() method, swap these two lines:

              DisplayNodes(Nodes(i).Children, newDiv, Level + 1)
              Container.Controls.Add(newDiv)

0
 
LVL 4

Expert Comment

by:gregg1ep00
ID: 16948017
Clarification:

Swap these two lines:
              DisplayNodes(Nodes(i).Children, newDiv, Level + 1)
              Container.Controls.Add(newDiv)

So they read like this:
              Container.Controls.Add(newDiv)
              DisplayNodes(Nodes(i).Children, newDiv, Level + 1)

0
 
LVL 6

Author Comment

by:fizch
ID: 16951377
Alright, I didn't have any luck with that either. However, don't worry about it now. This is not like me at all, but I downloaded microsoft's treeview and I have that working. It's got a lot more functionality than I would have ever put into mine. Sorry about wasting your time.
0
 
LVL 4

Expert Comment

by:gregg1ep00
ID: 16952856
Well, here's what we know, which may explain why I thought my last suggestion would work...

Your DisplayNodes() method creates the controls necessary for the TreeView and generates the client-side "onclick" handler for your image control by using the ClientId property of the "newDiv" element.  When you call into ClientId, it parses the control heirarchy and changes the Id attribute of the element, using all the Ids of that element's naming container heirarchy.  So it's important to call ClientId only when you have the naming container heirarchy set up, or else you'll run into the problem you're having.

So basically, when you first call into DisplayNodes(), you're passing the TreeViewContainer as the Container parameter.  When you get to the line where you set the client-side "onclick" handler and call newDiv.ClientId, the newDiv control must already be a member of the Container's control collection.  Then you can recursively call back into DisplayNodes(), and in THAT instance of the method, the Container's control heirarchy will already be set up.

Regardless, I'm glad to know that you found a solution that works.  Sorry we couldn't get it!  Good luck!  ;)

Cheers,
Greg
0
 
LVL 4

Expert Comment

by:gregg1ep00
ID: 16966362
fizch seems to have gotten his solution to work and posted his solution (used Microsoft's TreeView control).  Delete/Refund is fine with me.  I'm glad he found a solution that worked for him.
0
 

Accepted Solution

by:
RomMod earned 0 total points
ID: 16998663
Question closed - 500 points refunded.

Best regards,
RomMod
Experts Exchange
Community Support Moderator
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

User art_snob (http://www.experts-exchange.com/M_6114203.html) encountered strange behavior of Android Web browser on his Mobile Web site. It took a while to find the true cause. It happens so, that the Android Web browser (at least up to OS ver. 2.…
International Data Corporation (IDC) prognosticates that before the current the year gets over disbursing on IT framework products to be sent in cloud environs will be $37.1B.
This Micro Tutorial hows how you can integrate  Mac OSX to a Windows Active Directory Domain. Apple has made it easy to allow users to bind their macs to a windows domain with relative ease. The following video show how to bind OSX Mavericks to …
Migrating to Microsoft Office 365 is becoming increasingly popular for organizations both large and small. If you have made the leap to Microsoft’s cloud platform, you know that you will need to create a corporate email signature for your Office 365…

920 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now