Navigate
Home
ArticleWiki
Forum
Newsletter
Links
Tech News
Welcome Guest.
Username:

Password:

Remember me

ASP.NET TreeView, maintain state and getting rid of expand/collapse icons
Welcome, Guest. Please login or register.
February 09, 2012, 03:34:47 AM
11513 Posts in 1262 Topics by 496 Members
Latest Member: Beerdernill
Experts Round Table Network  |  Programming  |  .NET  |  ASP.NET TreeView, maintain state and getting rid of expand/collapse icons « previous next »
Pages: [1]
Author Topic: ASP.NET TreeView, maintain state and getting rid of expand/collapse icons  (Read 24709 times)
mattisflones

Offline Offline

Posts: 2


WWW
« on: September 01, 2006, 01:20:05 PM »

Finally, I got it! :-) No more limitations on navigation ever, ever, ever....
Thought i should share this with my fellow coders here at ERT for input, output and whatever.. please feel free to comment ..

This code does the following:
Lets you expand and collapse nodes as you prefer.
Lets you navigate to whatever page (Also pages unlisted in the SiteMap or DB) across your site without no trouble.
Maintains the state of the treeview.
Lets you get rid of those ridiculous + and - expand/collapse icons.

I used the OnSelectedNodeChanged event, and ShowExpandCollapse attrib of the treeview to make this work.

This is the treeview code for a master page:
<asp:TreeView ID="TreeView1" runat="server" DataSourceID="xmlDataSource" OnSelectedNodeChanged="TreeView1_SelectedNodeChanged"
ExpandDepth="0" MaxDataBindDepth="10" PopulateNodesFromClient="False" ShowExpandCollapse="False"
OnDataBound="TreeView1_DataBound">
</asp:TreeView>

Codebehind:

protected void Page_Load(object sender, EventArgs e)
{
  // Datastuff for binding the XML source or whatever here:
  ....


 // Disable ExpandDepth if the TreeView's expand/collapse
 // state is stored in session.
 if (Session["TreeViewState"] != null)
   TreeView1.ExpandDepth = -1;
}
public void TreeView1_SelectedNodeChanged(object sender, EventArgs e)
{
  //If the selected node is changed and we are working with the top node (If you want the ExpandCollapse func further dow, duplicate this part..)
  if (TreeView1.SelectedNode.Depth == 0)
    {
    TreeView1.CollapseAll();  //Collapse all nodes
    TreeView1.SelectedNode.Expand(); node//Expand the selected node
    }
  //Save the state of the treeview
  if (IsPostBack)
  {
    List<string> list = new List<string>(16);
    SaveTreeViewState(TreeView1.Nodes, list);
    Session["TreeViewState"] = list;
  }
  //All done, lets redirect to the new page
  if (IsPostBack)
  {
  // Here i use the "value" attribute of the treeview node, this must be used instead of the NavigateURL attribute whitch makes the
  //OnSelectedNodeChange event break in the first place   
    string fw = string.Empty;
    fw = TreeView1.SelectedValue.ToString();
    Response.Redirect(fw.ToString());
  }
}
//Save or reapply the state of the treeview
protected void TreeView1_DataBound(object sender, EventArgs e)
{
  if (Session["TreeViewState"] == null)
  {
    // Record the TreeView's current expand/collapse state.
    List<string> list = new List<string>(16);
    SaveTreeViewState(TreeView1.Nodes, list);
    Session["TreeViewState"] = list;
  }
  else
  {
  // Apply the recorded expand/collapse state to the TreeView.
  List<string> list = (List<string>)Session["TreeViewState"];
  RestoreTreeViewState(TreeView1.Nodes, list);
  }
}
//The save state func...
private void SaveTreeViewState(TreeNodeCollection nodes, List<string> list)
{
  // Recursivley record all expanded nodes in the List.
  foreach (TreeNode node in nodes)
  {
  if (node.ChildNodes != null && node.ChildNodes.Count != 0)
    {
    if (node.Expanded.HasValue && node.Expanded == true && !String.IsNullOrEmpty(node.Text))
    list.Add(node.Text);
    SaveTreeViewState(node.ChildNodes, list);
    }
  }
}
//The restore state func...
private void RestoreTreeViewState(TreeNodeCollection nodes, List<string> list)
{
  foreach (TreeNode node in nodes)
  {
  // Restore the state of one node.
  if (list.Contains(node.Text))
  {
  if (node.ChildNodes != null && node.ChildNodes.Count != 0 && node.Expanded.HasValue && node.Expanded == false)
  node.Expand();
  }
  else
  {
  if (node.ChildNodes != null && node.ChildNodes.Count != 0 && node.Expanded.HasValue && node.Expanded == true)
  node.Collapse();
  }
  // If the node has child nodes, restore their state, too.
  if (node.ChildNodes != null && node.ChildNodes.Count != 0)
  RestoreTreeViewState(node.ChildNodes, list);
  }
}

Credits:
Much of the code and ideas where borowed from Jeff Prosises MSDN Wicked Code article here:
http://msdn.microsoft.com/msdnmag/issues/06/06/WickedCode/default.aspx
(DotNET and Atlas example code included in article, worth a look@)

Happy coding! [cool]

For those of you that want the Data and xsl code, here it is:
Just as you know it, this way of doing it does not support breadcrumbs, so you might want to do a SiteMapDataSource thingey instead.
(I build my own custom breadcrumbs from the DataSource, but thats another chapter..)

Treeview DataBindings:
<DataBindings>
<asp:TreeNodeBinding DataMember="MenuItem" TextField="Text" ToolTipField="ToolTip" PopulateOnDemand="True" SelectAction="SelectExpand"
ValueField="MyVal" />
</DataBindings>

The Datasource build:
DataSet ds = new DataSet();
ConnectionStringSettings cs = ConfigurationManager.ConnectionStrings["DatabaseConnectionString1"];
using (SqlConnection conn = new SqlConnection(cs.ConnectionString))
{
string sql = "Select MenuID, Text, Description, ParentID, Page from Menu";
SqlDataAdapter da = new SqlDataAdapter(sql, conn);
da.Fill(ds);
da.Dispose();
}
ds.DataSetName = "Menus";
ds.Tables[0].TableName = "Menu";
DataRelation relation = new DataRelation("ParentChild",
ds.Tables["Menu"].Columns["MenuID"],
ds.Tables["Menu"].Columns["ParentID"],
true);
relation.Nested = true;
ds.Relations.Add(relation);
xmlDataSource.Data = ds.GetXml();

The xsl:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" encoding="utf-8"/>
<!-- Find the root node called Menus and call MenuListing for its children -->
<xsl:template match="/Menus">
<MenuItems>
<xsl:call-template name="MenuListing" />
</MenuItems>
</xsl:template>
<!-- Allow for recusive child node processing -->
<xsl:template name="MenuListing">
<xsl:apply-templates select="Menu" />
</xsl:template>
<xsl:template match="Menu">
<MenuItem>
<!-- Convert Menu child elements to MenuItem attributes -->
<xsl:attribute name="Text">
<xsl:value-of select="Text"/>
</xsl:attribute>
<xsl:attribute name="ToolTip">
<xsl:value-of select="Description"/>
</xsl:attribute>
<xsl:attribute name="MyVal">
<xsl:value-of select="Page"/>
<xsl:text>?Menu=</xsl:text>
<xsl:value-of select="MenuID"/>
</xsl:attribute>
<!-- Call MenuListing if there are child Menu nodes -->
<xsl:if test="count(Menu) > 0">
<xsl:call-template name="MenuListing" />
</xsl:if>
</MenuItem>
</xsl:template>
</xsl:stylesheet>


(The nicecoloured version of this is available here: http://forums.asp.net/thread/1387445.aspx)
« Last Edit: September 01, 2006, 01:22:42 PM by mattisflones » Logged

Yes, i am too...
COBOLdinosaur
ERT.com Admin

Offline Offline

Posts: 481



WWW
« Reply #1 on: September 01, 2006, 03:36:07 PM »

You know this has the potential to be the basis of a good article.  Posting it in forums so others can benefit from the knowledge will help a few people who run accross it, but even in the busiest of forums it will not get much exposure once it falls off the first page.

On the other hand if it was an ERT article it would be seen by hundreds of users every week and have a very long shelf life with a steady flow of traffic from Google. Our articles are averaging 1200 views a day and that is for only 35 pages of content.  Those 35 pages have had strong enough SEO applied to them so every one of them comes up top 10 in Google for their key words, and in August we had over 16,000 hits from Google.  That's an average of over 450 per page.  You won't get that exposure in a forum, and Google only represents part of the ERT traffic.  Links to ERT pages actually end up in many forums posted by members and sometimes even admins.  They also get posted in blogs, bookmark sites, community news and information sites, and other help sites.

ERT is ranked by Alexa in the top 100,000 and in the top 30,000 by technorati.  The rate of growth of the backlinks has been such that ERT pages carry enough weight on Google to rank ahead of much larger and well established sites.

So if you are trying to reach users who can use this information, you might want to think about investing a couple of hours turning this into an article.  The other authors, admins, and members will give you help to get a nice piece, that will continue to deliver help for many months or even years.

You retain control of content and presentaion; and retain copyright.  All ERT does is put a wrapper around it, and handle promotion.  Some suggestions to improve SEO might be made, but nothing goes on the site with your name on it unless you approve it.

Think about it, and if you want to take shot at publishing your work let me know, and we can move this to the content submission forum and start turning it into another high quality ERT content presentation.

Cd&
Logged
Pages: [1]
« previous next »
    Jump to: