Solved

ClientId for a control in a user control

Posted on 2006-06-20
15
1,051 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
ScreenConnect 6.0 Free Trial

At ScreenConnect, partner feedback doesn't fall on deaf ears. We collected partner suggestions off of their virtual wish list and transformed them into one game-changing release: ScreenConnect 6.0. Explore all of the extras and enhancements for yourself!

 
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
 
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

Back Up Your Microsoft Windows Server®

Back up all your Microsoft Windows Server – on-premises, in remote locations, in private and hybrid clouds. Your entire Windows Server will be backed up in one easy step with patented, block-level disk imaging. We achieve RTOs (recovery time objectives) as low as 15 seconds.

Question has a verified solution.

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

I have developed many web applications with asp & asp.net and to add and use a dropdownlist was always a very simple task, but with the new asp.net, setting the value is a bit tricky and its not similar to the old traditional method. So in this a…
This article discusses the ASP.NET AJAX ModalPopupExtender control. In this article we will show how to use the ModalPopupExtender control, how to display/show/call the ASP.NET AJAX ModalPopupExtender control from javascript, how to show/display/cal…
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …
Two types of users will appreciate AOMEI Backupper Pro: 1 - Those with PCIe drives (and haven't found cloning software that works on them). 2 - Those who want a fast clone of their boot drive (no re-boots needed) and it can clone your drive wh…

773 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