Maintain ASP.NET Tree Position on Postbacks Portland OR

Have you found ASP.NET lacking when it comes to keeping track of the last selected position between postbacks? You're not alone. Learn a JavaScript solution that does the trick.

Local Companies

Cascade Custom Software
503-922-0135
1000 SW Broadway
Portland, OR
Advantyx Software LLC
503-246-9299
6501 SW Macadam Ave
Portland, OR
Aravo Solutions
503-224-4049
2627 NW Nicolai St
Portland, OR
Axis Clinical Software Inc
503-292-3022
6443 SW Beaverton Hillsdale Hwy
Portland, OR
ApogeeInvent
403.407.9915
9999 SW Wilshire St. Ste. 100
Portland, OR
Cendix
503.789.2676
501 4th Street, Suite 741
Lake Oswego, OR
Artisan Software Tools Inc
503-245-6200
10220 SW Greenburg Rd
Portland, OR
Vision33
971-255-0162
The Lincoln Center, 10260 SW Greenburg Road, 4th Floor
Portland, OR
Paradigma Software
(503) 574-2776
6107 SW Murray Blvd #151
Beaverton, OR
ClearStar.net
360-892-0687
915 Broadway
Vancouver, WA

provided by: 
Originally published at Internet.com


The TreeView in ASP.NET 2.0 is a great control, but it seems to have one shortcoming: it isn't good at keeping track of the last selected position between postbacks. If you scroll down to the fiftieth item and expand a parent node, you have to start over at the top when the page returns.

In the previous version of .NET, you might have considered using the SmartNavigation feature instead. SmartNavigation is a property of a Web page. It is a Boolean that you can set in the Page directive or code behind. A Page directive with this attribute set to true may look like this: <%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb"
Inherits="_Default" SmartNavigation="true" %>

However, as many have noted, SmartNavigation has issues. In fact, Microsoft has deprecated this feature in ASP.NET 2.0 and added the MaintainScrollbackPositionOnPostback feature (that's a mouthful). Unfortunately, I haven't had a lot of luck with that one either (I'll explain why shortly).

This article shows where the SmartNavigation and MaintainScrollbackPositionOnPostback features fall short in maintaining tree position on postback and provides a JavaScript solution that seems to do the trick, even for complicated Web pages.

Bye-Bye SmartNavigation, Hello MaintainScrollbackPositionOnPostback

SmartNavigation is supposed to eliminate page flashing due to navigation. It does this by approximating IFrames and rendering only what has changed. SmartNavigation also is supposed to persist the scroll position, persist focused elements, and retain the last page in the browser's history. Unfortunately, even Microsoft knows SmartNavigation is broken. Check the MSDN help documentation and you will see that SmartNavigation is considered obsolete. Check Google and you will find a plethora of threads and discussions about the problems SmartNavigation has.

Next.

ASP.NET 2.0 introduces MaintainScrollbackPositionOnPostback. Like SmartNavigation, you can also set it to true or false in code or in the Page property: <%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb"
Inherits="_Default" MaintainScrollPositionOnPostback="true" %>

Quite literally, this property/attribute is supposed to maintain scroll position. Unfortunately it seems to do it only on the page itself. Hence, if you are in a node in a TreeView that is nested in a panel or UserControl, this feature will return you to that control but not a node in that control.

In short, MaintainScrollbackPositionOnPostback is a good feature if you have a page that scrolls. However, if your page is fixed-like an application might be-then it isn't going to help. If the only thing on the page is a long list that scrolls-like a TreeView-then this is the feature for you.

Maintaining Scroll Position within a TreeView

Recently, I developed a Web application that was sort of "Windowsy." That is, each Web page took up the whole screen but did not scroll. Controls within the pages scrolled like a TreeView for navigation and like a grid, but not the page itself. This application had sortable, hierarchical data listed in an n-nested TreeView. The problem was that sometimes the volume of data was extensive, necessitating annoying scrolling and re-scrolling as one navigated through the tree. Determined to resolve this problem, I devised the following solution.

First, the TreeView knows which node is selected because SelectedNode is a property of the TreeView control. This information has to be stored somewhere, and what is selected ultimately is rendered as HTML. If I know the ID of the selected HTML control, then I should be able to scroll and focus it. Sure enough, if you look at the source HTML of a page with a TreeView on it, you will find the declaration of a hidden tag-think text box-whose ID is approxximately TreeViewx_SelectedNode: value="TreeView1t54" />

With this knowledge, the idea is that a hidden input control is basically a textbox and all you need to do is figure out what the contents are. A TreeView is rendered as an HTML table-that's all ASP.NET controls are, little HTML code generators-and the value field is the client identifier of a table cell, a tag representing the node. So find the ID of the cell tag, scroll it into view, and you are done.

[Note to ASP.NET team: This should be a property of the TreeView. Thank you.]

To demonstrate, I wrote some code to generate a really full TreeView. The Page_Load event injects some JavaScript to find and focus the table cell (see Listing 1) and the tag's onload event calls this injected function.

Listing 1: The Code Behind That Fills a Treeview and Injects the JavaScript Imports System.Collections.Generic Partial Class _Default Inherits System.Web.UI.Page Protected Sub Page_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load InjectLoadEvent() If (IsPostBack) Then Return TreeView1.Nodes.Clear() Dim chicken As New TreeNode("Chicken") TreeView1.Nodes.Add(chicken) Dim beef As New TreeNode("Beef") TreeView1.Nodes.Add(beef) Dim pork As New TreeNode("Pork") TreeView1.Nodes.Add(pork) Dim fish As New TreeNode("Fish") TreeView1.Nodes.Add(fish) chicken.ChildNodes.Add(New TreeNode("Crepes Florentine with Buffalo Chicken")) fish.ChildNodes.Add(New TreeNode("Linguine with White Clam Sauce")) pork.ChildNodes.Add(New TreeNode("Pork Loin with Peanut and Madarin Orange Sauce")) beef.ChildNodes.Add(New TreeNode("Standing Rib Roast with Fennel and Blue Cheese Potatoes")) ' We need a bunch of stuff here so we will add some stubs Dim I As Integer For I = 1 To 50 chicken.ChildNodes.Add(New TreeNode("Placeholder " + I.ToString())) fish.ChildNodes.Add(New TreeNode("Placeholder " + I.ToString())) pork.ChildNodes.Add(New TreeNode("Placeholder " + I.ToString())) beef.ChildNodes.Add(New TreeNode("Placeholder " + I.ToString())) Next TreeView1.CollapseAll() End Sub Public Sub InjectLoadEvent() Dim script As String = _ "function LoadEvent()" + _ "{{" + _ " try" + _ " {{" + _ " var elem = document.getElementById('{0}_SelectedNode');" + _ " if(elem != null )" + _ " {{" + _ " var node = document.getElementById(elem.value);" + _ " if(node != null)" + _ " {{" + _ " node.scrollIntoView(true);" + _ " {1}.scrollLeft = 0;" + _ " }}" + _ " }}" + _ " }}" + _ " catch(oException)" + _ " {{}}" + _ "}}" Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), "LoadEvent", _ String.Format(script, TreeView1.ClientID, Panel1.ClientID), True) End Sub End Class

Listing 2 shows the complete page.

Listing 2: The ASP Code That Defines the Appearance of this Relatively Simple Page <%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %> Focus Tree Node on </P><i>Author:</i> Paul Kimmel<br /><br /><a href="http://www.developer.com/net/asp/article.php/3643956" target="_blank">Read article at Internet.com site</a> </div> </div> <div id="ctl00_contentMainLeft_rptParagraph_ctl01_ctlAdDisplayText_pnlAd1" class="AdsText"> <script type="text/javascript"><!-- document.write('<SCR'+'IPT src="http://snap9.advertserve.com/advertpro/servlet/view/text/unique/javascript/strip?total=3&layout=vertical&margin=0&padding=6&zid=5&pid=34&custom1=109&custom2=923620&custom3=224&custom4=OR&custom5=Portland&custom6=0&custom7=computer+hardware&custom8=.NET+Courses&custom9=30735&custom10=5218070093&random='+Math.floor(89999999*Math.random()+10000000)+'&millis='+new Date().getTime()+'" language="JavaScript" type="text/javascript"></SCR'+'IPT>'); //--></script> </div> <div class="ArticleParagraph"> <h2 id="ctl00_contentMainLeft_rptParagraph_ctl02_divParagraphTitle2"> Featured Local Company </h2> <div class="ArticleParagraphBody"> <b>Cascade Custom Software</b><br /><br />503-922-0135<br /> 1000 SW Broadway<br />Portland, OR<br /> <script language="javascript"> document.write(unescape("%3C%70%3E%3C%62%3E%49%66%20%79%6F%75%20%77%61%6E%74%20%74%6F%20%73%65%65%20%79%6F%75%72%20%63%6F%6D%70%61%6E%79%20%66%65%61%74%75%72%65%64%20%61%62%6F%76%65%2C%20%3C%61%20%68%72%65%66%3D%22%68%74%74%70%3A%2F%2F%73%75%62%73%63%72%69%62%65%2E%64%69%72%65%63%74%6F%72%79%6D%2E%63%6F%6D%2F%72%65%67%69%73%74%65%72%2E%61%73%70%78%3F%53%69%74%65%49%64%3D%31%30%26%41%72%74%69%63%6C%65%49%64%3D%39%32%33%36%32%30%26%41%74%74%72%69%62%75%74%69%6F%6E%49%64%3D%32%32%34%26%43%6C%61%73%73%49%64%3D%30%22%20%74%61%72%67%65%74%3D%22%62%6C%61%6E%6B%22%3E%72%65%67%69%73%74%65%72%20%66%6F%72%20%61%20%66%72%65%65%20%6C%69%73%74%69%6E%67%3C%2F%61%3E%2E%3C%2F%62%3E%3C%2F%70%3E")); </script></p> </div> </div> <div id="ctl00_contentMainLeft_rptParagraph_ctl02_ctlAdDisplayText_pnlAd1" class="AdsText"> <script type="text/javascript"><!-- document.write('<SCR'+'IPT src="http://snap9.advertserve.com/advertpro/servlet/view/text/unique/javascript/strip?total=3&layout=vertical&margin=0&padding=6&zid=5&pid=34&custom1=109&custom2=923620&custom3=224&custom4=OR&custom5=Portland&custom6=0&custom7=computer+hardware&custom8=.NET+Courses&custom9=30735&custom10=5218070093&random='+Math.floor(89999999*Math.random()+10000000)+'&millis='+new Date().getTime()+'" language="JavaScript" type="text/javascript"></SCR'+'IPT>'); //--></script> </div> <div id="ctl00_contentMainLeft_ctlRelatedArticlesBottom_divArticleRelated" class="Related"> <div class="RelatedHeader">Related Articles</div> <div class="RelatedBody"> <a class="RelatedLink" href="Displaying_XML_in_a_Swing_JTree_Portland_OR-r924039-Portland_OR.html" title="Displaying XML in a Swing JTree Portland OR">Displaying XML in a Swing JTree Portland OR</a> <div class="RelatedDesc">Learn how to create a tree model that displays an XML document structure.</div> </div> <div class="RelatedBody"> <a class="RelatedLink" href="PC_Registry_Software_Portland_OR-r1140830-Portland_OR.html" title="PC Registry Software Portland OR">PC Registry Software Portland OR</a> </div> <div class="RelatedBody"> <a class="RelatedLink" href="ProactiveNet_IT_Assistance_Portland_OR-r935029-Portland_OR.html" title="ProactiveNet IT Assistance Portland OR">ProactiveNet IT Assistance Portland OR</a> </div> <div class="RelatedBody"> <a class="RelatedLink" href="Caching_Solutions_in_Java_Portland_OR-r923889-Portland_OR.html" title="Caching Solutions in Java Portland OR">Caching Solutions in Java Portland OR</a> </div> <div class="RelatedBody"> <a class="RelatedLink" href="Creating_Ajax_Web_Applications_Using_the_Google_Web_Toolkit_GWT_and_Java_Portland_OR-r923637-Portland_OR.html" title="Creating Ajax Web Applications Using the Google Web Toolkit (GWT) and Java Portland OR">Creating Ajax Web Applications Using the Google Web Toolkit (GWT) and Java Portland OR</a> </div> <div class="RelatedBody"> <a class="RelatedLink" href="DeTroubler_Backup_Platform_Portland_OR-r959654-Portland_OR.html" title="DeTroubler Backup Platform Portland OR">DeTroubler Backup Platform Portland OR</a> </div> <div class="RelatedBody"> <a class="RelatedLink" href="FlyGrid_Net_Data_Management_Portland_OR-r952405-Portland_OR.html" title="FlyGrid.Net Data Management Portland OR">FlyGrid.Net Data Management Portland OR</a> </div> <div class="RelatedBody"> <a class="RelatedLink" href="How_to_Implement_and_Utilize_URL_Rewriting_with_ASP_NET_Portland_OR-r923908-Portland_OR.html" title="How to Implement and Utilize URL Rewriting with ASP.NET Portland OR">How to Implement and Utilize URL Rewriting with ASP.NET Portland OR</a> </div> <div class="RelatedBody"> <a class="RelatedLink" href="Family_Tree_Maker_Portland_OR-r952696-Portland_OR.html" title="Family Tree Maker Portland OR">Family Tree Maker Portland OR</a> </div> <div class="RelatedBody"> <a class="RelatedLink" href="Dont_Let_Memory_Leaks_Reduce_Your_Ajax_Application_Efficiency_Portland_OR-r923676-Portland_OR.html" title="Don't Let Memory Leaks Reduce Your Ajax Application Efficiency Portland OR">Don't Let Memory Leaks Reduce Your Ajax Application Efficiency Portland OR</a> </div> </div> <div id="ctl00_contentMainLeft_ctlTracking_pnlTracking" class="AdsText"> <script type="text/javascript"><!-- document.write('<SCR'+'IPT src="http://snap9.advertserve.com/advertpro/servlet/view/text/unique/javascript/strip?total=1&layout=vertical&margin=0&padding=1&zid=23&pid=34&custom1=109&custom2=923620&custom3=224&custom4=OR&custom5=Portland&custom6=7_10_109_923620_OR_Portland&custom7=computer+hardware&custom8=.NET+Courses&custom9=30735&custom10=5218070093&random='+Math.floor(89999999*Math.random()+10000000)+'&millis='+new Date().getTime()+'" language="JavaScript" type="text/javascript"></SCR'+'IPT>'); //--></script> </div> </div> <div class="mainRight"> <div id="ctl00_contentMainRight_ctlRelatedShows_divShowRelated" class="Rhs"> <div class="ShowsHeader">Related Local Events</div> <div class="ShowsBody"> <a class="ShowTitle" href="http://www.nielsenbusinessmedia.com/" target="blank">WOOD TECHNOLOGY CLINIC & SHOW 2010</a><br /> Dates: 3/9/2010 - 3/11/2010<br /> <b>Location:</b> Oregon Convention Center<br />Portland, OR<br /> <a href="javascript:showBranch('ShowId47828');">View Details</a><br /> <div style="display: none;" id="ShowId47828"> Times:8am-8pm<br /> Phone:646 654 4500<br /> <br /><b>Address:</b><br /> 777 NE Martin Luther King Jr. Blvd <br /> Portland, OR<br /> <br /><b>Description:</b><br />Exposition and Conference for the Wood Processing Industry<br /> </div> <hr class="Hr" /> <a class="ShowTitle" href="http://www.aeanet.org/events/EventsCatalog.cfm?Product_Major=OR070901" target="blank">Party in the Pinot</a><br /> Dates: 7/25/2009 - 7/25/2009<br /> <b>Location:</b> Oswego Hills Winery<br />West Linn, OR<br /> <a href="javascript:showBranch('ShowId61179');">View Details</a><br /> <div style="display: none;" id="ShowId61179"> Times:06:00 PM - 11:00 PM<br /> Phone:(503) 624-6050<br /> <br /><b>Address:</b><br /> 450 Rosemont Rd <br /> West Linn, OR<br /> <br /><b>Description:</b><br />Celebrate Oregon¡¯s High-Tech Industry with over 400 of the area¡¯s top technology executives and service providers at TechAmerica's (formerly AeA) Annual Gala Party in the Pinot!<br /> </div> </div> <div class="ShowsFooter"> </div> </div> <div id="ctl00_contentMainRight_ctlRelatedArticles_divArticleRelated" class="Related"> <div class="RelatedHeader">Related Articles</div> <div class="RelatedBody"> <a class="RelatedLink" href="Family_Tree_Maker_Portland_OR-r952696-Portland_OR.html" title="Family Tree Maker Portland OR">Family Tree Maker Portland OR</a> <div class="RelatedDesc">Family Tree Maker is a neat little package of genealogy software designed to aid in either your small project or all-out research. It's easily understandable and navigable, presenting many options such as a scrapbook of each person, allowing pictures to be embedded, medical information, multiple spouses etc.</div> </div> <div class="RelatedBody"> <a class="RelatedLink" href="How_to_Implement_and_Utilize_URL_Rewriting_with_ASP_NET_Portland_OR-r923908-Portland_OR.html" title="How to Implement and Utilize URL Rewriting with ASP.NET Portland OR">How to Implement and Utilize URL Rewriting with ASP.NET Portland OR</a> </div> <div class="RelatedBody"> <a class="RelatedLink" href="Creating_Ajax_Web_Applications_Using_the_Google_Web_Toolkit_GWT_and_Java_Portland_OR-r923637-Portland_OR.html" title="Creating Ajax Web Applications Using the Google Web Toolkit (GWT) and Java Portland OR">Creating Ajax Web Applications Using the Google Web Toolkit (GWT) and Java Portland OR</a> </div> <div class="RelatedBody"> <a class="RelatedLink" href="Caching_Solutions_in_Java_Portland_OR-r923889-Portland_OR.html" title="Caching Solutions in Java Portland OR">Caching Solutions in Java Portland OR</a> </div> <div class="RelatedBody"> <a class="RelatedLink" href="Displaying_XML_in_a_Swing_JTree_Portland_OR-r924039-Portland_OR.html" title="Displaying XML in a Swing JTree Portland OR">Displaying XML in a Swing JTree Portland OR</a> </div> <div class="RelatedBody"> <a class="RelatedLink" href="ProactiveNet_IT_Assistance_Portland_OR-r935029-Portland_OR.html" title="ProactiveNet IT Assistance Portland OR">ProactiveNet IT Assistance Portland OR</a> </div> <div class="RelatedBody"> <a class="RelatedLink" href="DeTroubler_Backup_Platform_Portland_OR-r959654-Portland_OR.html" title="DeTroubler Backup Platform Portland OR">DeTroubler Backup Platform Portland OR</a> </div> <div class="RelatedBody"> <a class="RelatedLink" href="Dont_Let_Memory_Leaks_Reduce_Your_Ajax_Application_Efficiency_Portland_OR-r923676-Portland_OR.html" title="Don't Let Memory Leaks Reduce Your Ajax Application Efficiency Portland OR">Don't Let Memory Leaks Reduce Your Ajax Application Efficiency Portland OR</a> </div> <div class="RelatedBody"> <a class="RelatedLink" href="PC_Registry_Software_Portland_OR-r1140830-Portland_OR.html" title="PC Registry Software Portland OR">PC Registry Software Portland OR</a> </div> <div class="RelatedBody"> <a class="RelatedLink" href="FlyGrid_Net_Data_Management_Portland_OR-r952405-Portland_OR.html" title="FlyGrid.Net Data Management Portland OR">FlyGrid.Net Data Management Portland OR</a> </div> </div> <div class="Rhs"> <iframe src="http://myarticles-api.directorym.com/iFrame_v6/RatingAndSaved.aspx?ArticleId=923620&AvgRating=0&NumRating=0" width="300" height="140" frameborder="0" scrolling="no" marginheight="0" marginwidth="0"></iframe> </div> <div class="Rhs"> <iframe src="http://myarticles-api.directorym.com/iFrame_v6/LoginOrJoin.aspx" width="300" height="275" frameborder="0" scrolling="no" marginheight="0" marginwidth="0"></iframe> </div> <div class="Rhs"> <div class="RhsHeader RecommendHeader">Save Articles.DirectoryM.net</div> <div class="RhsBody"> <div class="RhsBodyItem"> <a href="http://articles.directorym.net/rss.aspx?ArticleregionId=923620-portland_or" id="ctl00_contentMainRight_ctlRecommend_lnkRss" rel="alternate" type="application/rss+xml"> <img id="ctl00_contentMainRight_ctlRecommend_imgRecommendRss" class="ImageLink" title="Rss" src="App_Themes/templateDarkBlueWAdSense_en-US/Images/RecommendRss.png" alt="Rss" height="16" width="16" border="0" /> RSS feed</a> </div> <div class="RhsBodyItem"> <a href="http://del.icio.us/post" onclick="window.open('http://del.icio.us/post?v=4&noui&jump=close&url='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title), 'delicious','toolbar=no,width=700,height=400'); return false;"> <img id="ctl00_contentMainRight_ctlRecommend_imgRecommendDelicious" class="ImageLink" title="Delicious" src="App_Themes/templateDarkBlueWAdSense_en-US/Images/RecommendDelicious.gif" alt="Delicious" height="10" width="10" border="0" /> Bookmark this on Delicious</a> </div> <div class="RhsBodyItem"> <a href="http://digg.com/submit?phase=2" id="ctl00_contentMainRight_ctlRecommend_lnkDigg" onclick="window.open('http://digg.com/submit?phase=2&url='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title)); return false;"> <img id="ctl00_contentMainRight_ctlRecommend_imgRecommendDigg" class="ImageLink" title="Digg" src="App_Themes/templateDarkBlueWAdSense_en-US/Images/RecommendDigg.gif" alt="Digg" height="20" width="100" border="0" /></a> </div> <div class="RhsBodyItem"> <a href="http://add.my.yahoo.com/rss?url=http%3a%2f%2farticles.directorym.net%2frss.aspx%3fArticleregionId%3d923620-portland_or" id="ctl00_contentMainRight_ctlRecommend_lnkYahoo"><img id="ctl00_contentMainRight_ctlRecommend_imgRecommendYahoo" class="ImageLink" title="Add To My Yahoo" src="App_Themes/templateDarkBlueWAdSense_en-US/Images/RecommendYahoo.gif" alt="Add To My Yahoo" height="17" width="91" border="0" /></a> </div> <div class="RhsBodyItem"> <a href="http://fusion.google.com/add?feedurl=http%3a%2f%2farticles.directorym.net%2frss.aspx%3fArticleregionId%3d923620-portland_or" id="ctl00_contentMainRight_ctlRecommend_lnkGoogle"><img id="ctl00_contentMainRight_ctlRecommend_imgRecommendGoogle" class="ImageLink" title="Add To My Google" src="App_Themes/templateDarkBlueWAdSense_en-US/Images/RecommendGoogle.gif" alt="Add To My Google" height="17" width="104" border="0" /></a> </div> <div class="RhsBodyItem"> <a href="javascript:bookmarksite(document.title, location.href)">Bookmark this page</a> </div> </div> <div class="RhsFooter"> </div> </div> <div id="ctl00_contentMainRight_AdSpacer1_spacer" style="height:544px;"></div> </div> </div> <div class="footer"> <br /><hr class="HrFooter" /> <br />Copyright © BET Information Systems, Inc. All rights reserved. <br /><br /> </div> </form> </div> <div id="ctl00_pnlAnalytics"> <script type="text/javascript"> var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E")); </script> <script type="text/javascript"> var pageTracker = _gat._getTracker("UA-722551-18"); pageTracker._initData(); pageTracker._trackPageview(); </script> </div> <!-- u: articles.directorym.net/Articleregion.aspx?ArticleregionId=923620-portland_or a: 6.0.132.28008 d: 5.1.157.0 b: 5.1.131.0 s: 2 --> </body> </html>