How to collapse all branches in a treeview except for selected branch

Thank you for anyone who can help me out here. I’ve scoured the internet for solutions, and all are only partial solutions.

I have a TreeView that is bound to a SiteMapDataSource.

Here is my question: how can I collapse all items except for the branch the user selected?

Here is my code for the SiteMapDataSource and the Treeview:

<asp:SiteMapDataSource ID="smdsProdcutsMenu" runat="server" StartingNodeUrl="~/Products/products.aspx" />

<asp:TreeView ID="tvCategory" runat="server" CssClass="Treeview" NodeWrap="true"
   DataSourceID="smdsProdcutsMenu" MaxDataBindDepth="3" ShowLines="True"  
   ExpandDepth="3" ontreenodeexpanded="TreeNodeExpanded">
   <SelectedNodeStyle BackColor="White" Font-Bold="True" ForeColor="Blue" />
</asp:TreeView>

Here is the code that runs when the user clicks any item in the treeview.

Protected Sub TreeNodeExpanded(sender As Object, e As System.Web.UI.WebControls.TreeNodeEventArgs)
        ' This is triggered whenever a user clicks an item in the treeview.
tvCategory.CollapseAll()

' How do I collapse everything except for the branch the user selected?
End Sub

Any ideas? Thank you.

Hi HatesSunligh…,

According to your description, I know you want to collapse all items except for the branch the user selected.

If so, I made a test in my application, and it could collapse all items except for the branch the user selected.so please refer to the code below:

The source page code:

<asp:TreeView ID="tvCategory" runat="server"  OnSelectedNodeChanged="tvCategory_SelectedNodeChanged" >
           <Nodes>
               <asp:TreeNode Text="node1" Value="node1">
                   <asp:TreeNode Text="node11" Value="node11"></asp:TreeNode>
                   <asp:TreeNode Text="node12" Value="node12"></asp:TreeNode>
                   <asp:TreeNode Text="node13" Value="node13"></asp:TreeNode>
               </asp:TreeNode>
               <asp:TreeNode Text="node2" Value="node2">
                   <asp:TreeNode Text="node21" Value="node21">
                       <asp:TreeNode Text="node211" Value="node211"></asp:TreeNode>
                   </asp:TreeNode>
                   <asp:TreeNode Text="node22" Value="node22"></asp:TreeNode>
               </asp:TreeNode>
               <asp:TreeNode Text="node3" Value="node3">
                   <asp:TreeNode Text="node31" Value="node31"></asp:TreeNode>
               </asp:TreeNode>
           </Nodes>
   <SelectedNodeStyle BackColor="White" Font-Bold="True" ForeColor="Blue" />
</asp:TreeView>

The aspx.ce page code:

namespace TestAndDemos.Test
{
    public partial class TreeView : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            tvCategory.CollapseAll();
        }
        protected void tvCategory_SelectedNodeChanged(object sender, EventArgs e)
        {
            tvCategory.CollapseAll();
            TreeNode node= tvCategory.SelectedNode;
            node.ExpandAll();
        }
    }
}

If you need any other help, please feel free to post in this forum.

Best Regards,

May

Thanks for your response. I have one important question about your approach. 

It looks to me like you’re manually populating the treeview. Am I reading this correctly, because I am binding my treeview to my sitemap file, which is very large and subject weekly change.  Or is that a red herring?

On another note, I have already established that "selectednodechanged" does not do anything, even by testing something as simple as lblTest.text = "You just selected a different node."  

Is it because I am binding my treeview to the sitemap?  

Hi HatesSunligh,

Thank you for you reply.

HatesSunlight

It looks to me like you’re manually populating the treeview

About the above point what you said. Yes, this data is filled manaually, however, it os only used for test that the TreeView control could achieve CollapseAll()  and ExpandAll() function.

If you have any other questions, please feel freely to post this forum

Best Regards,

May

Unfortunately, it’s still not working for me. Here is the code from my latest iteration.

Script block: 

<script runat="server">
    
    Protected Sub SetupPage(sender As Object, e As System.EventArgs) Handles Me.Load
        ' Don't do anything here so we can isolate the selectednodechanged event & sub
    End Sub
    
    Protected Sub SelectedNodeChanged(sender As Object, e As System.EventArgs)
        tvCategory.CollapseAll()
    End Sub
</script>

SitmapDataSource & Treeview: 

<asp:SiteMapDataSource ID="sdmsCategory" runat="server" StartingNodeUrl="~/Products/products.aspx" />                    
<asp:TreeView ID="tvCategory" runat="server" DataSourceID="sdmsCategory" onselectednodechanged="SelectedNodeChanged">
</asp:TreeView>

I kept my code as simple as possible and confirmed, once again, that SelectedNodeChanged does nothing for me. If the event was triggered, the treeview should have collapsed — it didn’t. Not a single branch of the tree. It was all fully
expanded.

Hi HatesSunlight,

In your SelectedNodeChanged() method ,you  need to get the selected node ,then expand all node:

Protected Sub SelectedNodeChanged(sender As Object, e As System.EventArgs)
            tvCategory.CollapseAll();
            TreeNode node= tvCategory.SelectedNode;
            node.ExpandAll();
    End Sub

When you change selected node,it will first collaspe all ,then expand current node.

I suggest that you should set a breakpoint on the method above,see if it can find the selectedNode,expand its sub nodes.

Best Regards,

Kevin Shen.

At the risk of sounding like a broken record, I did literally what you wrote, and it didn’t work. If this event were triggered, then this — and I post it again — would have worked.

Protected Sub SelectedNodeChanged(sender As Object, e As System.EventArgs)
        lblTest.Text="You changed a node."
End Sub

When I change any node, this event is not triggered once.

To erase any doubt, I’m posting the entire page, minus any confidential information, just in case there’s something very subtle that didn’t get flipped.

I’ve boldfaced the relevant sections of code.

<%@ Master Language="VB" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
    
    Protected Sub SetupPage(sender As Object, e As System.EventArgs) Handles Me.Load
        ' Don't do anything here so we can isolate the selectednodechanged event & sub
    End Sub
    
    Protected Sub SelectedNodeChanged(sender As Object, e As System.EventArgs)
        lblTest.Text = "You changed a node."
                
        tvCategory.CollapseAll()
        Dim node As TreeNode = tvCategory.SelectedNode
        node.ExpandAll()
    End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <link href="../../CSS_Styles/Product_Subpage.css" rel="stylesheet" type="text/css" />
    <title>[Snip]</title>
    <asp:ContentPlaceHolder ID="head" runat="server">
    </asp:ContentPlaceHolder>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
</head>
<body>
    <form id="form1" runat="server">
    <div id="div_Frame">
        <asp:Label ID="lblTest" runat="server" Text="Label"></asp:Label>
        <div id="div_Header">
            <p>[Snip]</p>
        </div>
        <div id="div_Menu">
            <asp:SiteMapDataSource ID="smdsRoot" runat="server" />
            <asp:Menu ID="mvRoot" runat="server" DataSourceID="smdsRoot" Orientation="Horizontal"
                StaticDisplayLevels="2" MaximumDynamicDisplayLevels="1" ItemWrap="True" StaticEnableDefaultPopOutImage="False">
                <DynamicHoverStyle CssClass="DynamicHoverStyle" />
                <DynamicMenuItemStyle CssClass="DynamicMenuItemStyle" />
                <DynamicMenuStyle CssClass="DynamicMenuStyle" />
                <DynamicSelectedStyle CssClass="DynamicSelectedStyle" />
                <StaticMenuStyle CssClass="StaticMenuStyle" />
                <StaticSelectedStyle CssClass="StaticSelectedStyle" />
            </asp:Menu>
        </div>
        <div id="div_Middle">
            <div id="div_Nav_L">
                <h2>Product Submenu</h2>
                <p>
                    <asp:SiteMapDataSource ID="sdmsCategory" runat="server" StartingNodeUrl="~/Products/products.aspx" />
                    <asp:TreeView ID="tvCategory" runat="server" DataSourceID="sdmsCategory" OnSelectedNodeChanged="SelectedNodeChanged"
                        NodeWrap="True">
                    </asp:TreeView>
                </p>
            </div>
            <div id="div_Body_R">
                <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
                </asp:ContentPlaceHolder>
            </div>
        </div>
        <div id="div_Footer">
            <p>[Snip]</p>
        </div>
    </div>
    </form>
</body>
</html>

Obviously, I’m not showing the play-by-play of all the approaches and iterations I’ve gone through over the last few days, but I find myself increasingly frustrated.

The code shown by others in response to my question all make logical sense. No errors are thrown by the browser or by Visual Studio debug, so clearly the code is grammatically correct and legal.

Why the code isn’t working is clearly puzzling. My sitemap is five layers deep, so there are clearly nodes.  In fact the nodes are called "sitemapnode" — so there is no doubt in my mind that the sitemap is a tree structure. Why my treeview will not respond
to "selectednodechanged" is truly puzzling.

Because this is a problem I’m trying to solve for a paid production page, I have to move on and do a workaround — i.e., another approach altogether — my mind is now on other things. But if anyone can show me (a) where I went wrong, and/or (b) an approach
that clearly works with a treeview bound to a sitemapdatasource, I’m still interested.

Do you want to expand the node and all it’s child node or just the node and immediate children? If you want to do just immediate, try node.Expand() instead of ExpandAll() 

Here’s a different way of explaining what I was trying to do.  Here is an example tree structure. If I click anywhere in branch 1, I want all other branches to collapse. If I click anywhere in branch 2, the other branches collapse, but I can expand whatever
child nodes exist in branch 2, etc.  When I click any node or leaf, I can see that the selected node property matches the item I clicked, but as I’ve consistently tested and repeated in this thread, "selectednodechanged" does not trigger, even though by reading
the selectednode property, it has indeed changed.

* Root Node

** Branch 1

*** Branch 1, Leaf 1

*** Branch 1, Leaf 2

*** Branch 1, Leaf 3

** Branch 2

*** Branch 2, Leaf 1

*** Branch 2, Leaf 2

** Branch 3

etc…

Leave a Reply