Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1057
  • Last Modified:

ClientId for a control in a user control

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
fizch
Asked:
fizch
  • 8
  • 5
1 Solution
 
gregg1ep00Commented:
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
 
fizchAuthor Commented:
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
 
gregg1ep00Commented:
Ok, a few questions:
1) Which version of .NET are you using?
2) What page event are you launching your "BuildTreeView()" method from?
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
fizchAuthor Commented:
1) I am using 1.1
2) Page_Load of the main page
0
 
gregg1ep00Commented:
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
 
fizchAuthor Commented:
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
 
gregg1ep00Commented:
Wow, ok.  I must be confusing myself now.  Sorry about that.  ;)

Can you give me an updated generated output?
Thx
0
 
fizchAuthor Commented:
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
 
gregg1ep00Commented:
In your DisplayNodes() method, swap these two lines:

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

0
 
gregg1ep00Commented:
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
 
fizchAuthor Commented:
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
 
gregg1ep00Commented:
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
 
gregg1ep00Commented:
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
 
RomModCommented:
Question closed - 500 points refunded.

Best regards,
RomMod
Experts Exchange
Community Support Moderator
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

  • 8
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now