ASP
NET
提供了一个功能强大的TreeView控件
但是它看起来有一个缺陷
它好像不能够跟蹤用户最后选择的一个节点
如果你滚动到第
个节点然后展开该节点
那么当单击链接页面进行回发后
你必须重新利用滚动条下拉到你想要的节点位置
在NET较早的版本里您可能考虑使用SmartNavigation这个特性SmartNavigation是Web页面指令的一个属性它的取值为布尔值一个设置为true的页面指令看起来类似如下
<%@ Page Language=VB AutoEventWireup=false CodeFile=Defaultaspxvb Inherits=_Default SmartNavigation=true %>
不过正如好多人已经注意到的SmartNavigation本身就有洗衣阿问题事实上微软也被这个问题所困扰以至于在ASPNET里添加了MaintainScrollbackPositionOnPostback属性而取代SmartNavigation 遗憾的是我在使用它们时感觉它们都有一些问题我稍后将进行解释
本文我将介绍SmartNavigation和MaintainScrollbackPositionOnPostback 在维护页面回发位置方面的缺点并提供如何利用Javascript来解决这个问题这个小技巧即使对复杂的Web页面也同样有效
再见了SmartNavigationeb欢迎MaintainScrollbackPositionOnPostback
SmartNavigation主要作用是减少页面导航时的闪动它主要利用适当的IFrames来进行这个工作并仅仅显示改变的部分SmartNavigation 同样被设计为能够维护页面位置元素焦点回发浏览器访问历史记录的作用遗憾的是即使微软知道SmartNavigation已经去掉但是检查MSDN文档您仍然能够看到SmartNavigation其实仅仅被定义为过时的 利用GOOGLE的搜索您可以搜到大家对SmartNavigation的讨论
下一步
ASPNET引进了MaintainScrollbackPositionOnPostback和SmartNavigation类似您可以在Page属性里设置它的值为true或者为false
<%@ Page Language=VB AutoEventWireup=false CodeFile=Defaultaspxvb Inherits=_Default MaintainScrollPositionOnPostback=true %>
非常简明这个属性/属性值对是用来维护页面位置的遗憾的是它只是维护页面的位置因为如果你在用户控件里使用了TreeView控件然后在页面里使用该用户控件那么页面在在回发后您将返回到用户控件的位置而不是TreeView节点位置
简单的说MaintainScrollbackPositionOnPostback只是用来维护页面的回发位置如果你的页面固定--也就是一个应用程序那样不需要进行利用滚动条进行上下滚动那么这个属性对你可能无用如果你的页面很常需要滚动那么你就需要利用该属性
在TreeView里维护控件的位置
最近我在开发一个Web应用程序Windowsy也就是每一个页面都会全屏显示而不是滚动页面里使用类TreeView来进行导航想列表一样进行显示但是页面本身不需要上下滚动但是问题是这里的数据列可能需要扩展使得页面出现滚动我准备使用如下的方式解决这个问题
首先利用TreeView控件的SelectedNode属性可以知道哪个节点被选取这个被选取的节点需要保存起来它最终会程序为HTML元素如果我知道了被选择HTML控件的ID那么我就可以滚动到该控件并设置该控件为当前焦点确实如果您看以下使用TreeView控件的页面HTML代码你将发现生成的一个隐藏<input>元素以及为textbox类型它的ID可能类似TreeViewx_SelectedNode
<input type=hidden name=TreeView_SelectedNode id=TreeView_SelectedNode value=TreeViewt />
有了这些知识你就知道该怎么做了基本方法是隐藏的Input是一个textbox我们要做的就是知道将来呈献的内容一个TreeView最终呈现为HTML表格节点的值被用来作为单元格的值<TD>元素呈现节点名称所以通过查找单元格ID并滚动到那里
为了具体说明做法我使用TreeView编写了一些代码在Page_Load时间里加载一段脚本来找到需要的单元格(参考下表)在<body>的onload时间里调用该函数
Imports System
Collections
Generic
Partial Class _Default
Inherits SystemWebUIPage
Protected Sub Page_Load(ByVal sender As Object _
ByVal e As SystemEventArgs) Handles MeLoad
InjectLoadEvent()
If (IsPostBack) Then Return
TreeViewNodesClear()
Dim chicken As New TreeNode(Chicken)
TreeViewNodesAdd(chicken)
Dim beef As New TreeNode(Beef)
TreeViewNodesAdd(beef)
Dim pork As New TreeNode(Pork)
TreeViewNodesAdd(pork)
Dim fish As New TreeNode(Fish)
TreeViewNodesAdd(fish)
chickenChildNodesAdd(New TreeNode(Crepes Florentine with Buffalo Chicken))
fishChildNodesAdd(New TreeNode(Linguine with White Clam Sauce))
porkChildNodesAdd(New TreeNode(Pork Loin with Peanut and Madarin Orange Sauce))
beefChildNodesAdd(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 = To
chickenChildNodesAdd(New TreeNode(Placeholder + IToString()))
fishChildNodesAdd(New TreeNode(Placeholder + IToString()))
porkChildNodesAdd(New TreeNode(Placeholder + IToString()))
beefChildNodesAdd(New TreeNode(Placeholder + IToString()))
Next
TreeViewCollapseAll()
End Sub
Public Sub InjectLoadEvent()
Dim script As String = _
function LoadEvent() + _
{{ + _
try + _
{{ + _
var elem = documentgetElementById({}_SelectedNode); + _
if(elem != null ) + _
{{ + _
var node = documentgetElementById(elemvalue); + _
if(node != null) + _
{{ + _
nodescrollIntoView(true); + _
{}scrollLeft = ; + _
}} + _
}} + _
}} + _
catch(oException) + _
{{}} + _
}}
PageClientScriptRegisterClientScriptBlock(MeGetType() LoadEvent _
StringFormat(script TreeViewClientID PanelClientID) True)
End Sub
End Class
下面的代码显示了页面的布局
<%@ Page Language=VB AutoEventWireup=false CodeFile=Defaultaspxvb Inherits=_Default %>
<!DOCTYPE html PUBLIC //WC//DTD XHTML Transitional//EN transitionaldtd>
<html xmlns= >
<head runat=server>
<title>Focus Tree Node on Postback</title>
</head>
<body onload=LoadEvent()>
<form id=form runat=server>
<div>
<asp:Panel ID=Panel runat=server Height=px Width=px ScrollBars=Both>
<asp:TreeView ID=TreeView runat=server>
<SelectedNodeStyle BackColor=#FF />
</asp:TreeView>
</asp:Panel>
</div>
</form>
</body>
</html>
下图显示了本例子运行的结果
最后下面的代码显示了javascript的注入方式
<script>
function LoadEvent()
{
try
{
var elem = documentgetElementById(TreeView_SelectedNode);
if(elem != null )
{
var node = documentgetElementById(elemvalue);
if(node != null)
{
nodescrollIntoView(true);
PanelscrollLeft = ;
}
}
}
catch(oException)
{}
}// >
</script>
用Javascript定义的LoadEvent函数将查找隐藏字段我们利用TreeView控件的ClientID 查找所有元素不过在嵌套多个TreeView控件后名称将变得非常长找到单元格的值后我使用scrollIntoView方法scrollLeft属性将让滚动条滚动当前位置