Solved

ClientId for a control in a user control

Posted on 2006-06-20
15
1,049 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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
1) I am using 1.1
2) Page_Load of the main page
0
 
LVL 4

Expert Comment

by:gregg1ep00
Comment Utility
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
Comment Utility
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
Comment Utility
Wow, ok.  I must be confusing myself now.  Sorry about that.  ;)

Can you give me an updated generated output?
Thx
0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 6

Author Comment

by:fizch
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
Question closed - 500 points refunded.

Best regards,
RomMod
Experts Exchange
Community Support Moderator
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

AJAX ModalPopupExtender has a required property "TargetControlID" which may seem to be very confusing to new users. It means the server control that will be extended by the ModalPopup, for instance, if when you click a button, a ModalPopup displays,…
In .NET 2.0, Microsoft introduced the Web Site.  This was the default way to create a web Project in Visual Studio 2005.  In Visual Studio 2008, the Web Application has been restored as the default web Project in Visual Studio/.NET 3.x The Web Si…
This video discusses moving either the default database or any database to a new volume.
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

743 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

15 Experts available now in Live!

Get 1:1 Help Now