网站导航(站点地图)

       一个网站,需要借助某个导航系统来帮助用户从一个页面跳转到另一个页面。我们知道,可以利用母版页帮助网站定义一个包含导航栏的模板,不过,仍然要由你来为导航栏填入内容。

       当然可以利用 ASP.NET 的控件集实现几乎所有的导航系统,但这需要大量的工作!幸好 ASP.NET 包括一组导航功能,它们可以大大简化你的工作。

       和 ASP.NET 所有的最佳功能一样,ASP.NET 导航灵活、可配置、可插入。它包含以下 3 部分:

  • 定义站点地图导航结构。这部分是 XML 站点地图,它(默认)保存在文件里。
  • 解析站点地图文件并转换为适当对象模型。这部分由 SiteMapDataSoruce 和 XmlSiteMapProvider 实现。
  • 利用站点地图信息显示用户当前位置并让用户能够方便的从一个页面跳转到另一个页面的简单方法。这部分由绑定到 SiteMapDataSoruce 控件提供,可以是浏览器路径链接、列表、菜单或树。

定义站点地图

       基于站点地图导航的起始点是站点地图提供程序。ASP.NET 只提供了一个站点地图提供程序 XmlSiteMapProvider ,它可以从一个 XML 文件里读取站点地图信息。XmlSiteMapProvider 在虚拟目录的根目录查找一个叫做 Web.sitemap 的文件。和所有站点地图提供程序一样,它的任务时抓取站点地图数据并创建相应的 SiteMap 对象。此后,这个 SiteMap 对象通过 SiteMapDataSource 对其他控件可用。

       下面是站点地图文件的基本结构:

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
  <siteMapNode title="Home" description="Root" url="~/Default.aspx">
    <siteMapNode title="Products" description="Our products" url="~/Products.aspx" >
      <siteMapNode title="Hardware" description="Hardware choices" url="~/Hardware.aspx" />
      <siteMapNode title="Software" description="Software choices" url="~/Software.aspx" />
    </siteMapNode>
 
    <siteMapNode title="Services" description="Services we offer" url="~/Services.aspx" >
      <siteMapNode title="Training" description="Training classes" url="~/Training.aspx" />
      <siteMapNode title="Consulting" description="Consulting services" url="~/Consulting.aspx" />
      <siteMapNode title="Support" description="Support plans" url="~/Support.aspx" />
    </siteMapNode>
  </siteMapNode>
</siteMap>

       为了保证有效性,站点地图必须遵守以下这些规则:

  • 以 <siteMap> 节点开始,后面跟一个 <siteMapNode> 元素,它代表默认主页。
  • 可用在根 <siteMapNode> 内嵌入无限多层 <siteMapNode> 元素。

       这个例子中,URL 使用了 ./ 语法,表示 Web 应用程序的根。这种风格并不是必须的,但强烈推荐,因为这样可以保证站点地图链接可以不管当前文件夹而被正确的解释。

       另一个限制是你不能为同一个 URL 创建两个或以上的站点地图节点。这个限制并不是导航系统固有的。它只是 XmlSiteMapProvider 的要求,因为 XmlSiteMapProvider 把 URL 作为唯一键。如果你创建自己的站点地图提供程序或者使用第三方的提供程序,就可以允许重复的 URL,不过仍然需要唯一的键值。

绑定站点地图

       定义了 Web.sitemap 文件之后,就随时可以在页面中使用它了。这正是使用母版页的地方,这样可以把导航控件定义为母版页的一部分并在所有页面里重用它。

<form id="form1" runat="server">
<table>
    <tr>
        <td style=" 226px; vertical-align: top">
 
        </td>
        <td style="vertical-align: top">
            <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server" />
        </td>
    </tr>
</table>
<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" />
</form>

       可以使用 TreeView 控件来做导航:

<asp:TreeView ID="treeNav" runat="server" DataSourceID="SiteMapDataSource1"></asp:TreeView>

image

       也可以同样方便的使用 Menu 控件:

<asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1"></asp:Menu>

image

导航路径

       ASP.NET 其实定义了 3 个导航控件:TreeView、Menu、SiteMapPath 。

       SiteMapPath 提供导航路径,它显示用户当前位置并允许使用链接回到更高的层级。它和其他导航控件(如 TreeView、Menu)有细微但却重要的区别。SiteMapPath 直接作用于 ASP.NET 导航模型,它并不从 SiteMapDataSource 获取自己的数据。因此,可以在没有 SiteMapDataSource 的页面上使用 SiteMapPath ,而且对 SiteMapDataSource 的属性的修改也不会影响 SiteMapPath 。

       SiteMapPath 典型的应用是在母版页上,这样它就可以显示在所有的内容页上。SiteMapPath 控件在告知用户当前位置以及提供用户在层次结构间向上跳转方面都很有用(只能向上跳转)。不过,你也必须将其结合其他导航控件一起使用,那样才能让用户在站点地图层次中向下跳转。

       下例在母版页的 2 处都放置了 SiteMapPath 控件:

<form id="form1" runat="server">
<div>
    &nbsp;<table>
        <tr>
            <td style=" 226px; vertical-align: top;">
                <asp:SiteMapPath ID="SiteMapPath1" runat="server">
                </asp:SiteMapPath>
                <br />
                <br />
                <asp:TreeView ID="TreeView1" runat="server" DataSourceID="SiteMapDataSource1">
                </asp:TreeView>
                <!--<asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1">
    </asp:Menu>-->
            </td>
            <td style="vertical-align: top;">
                <asp:SiteMapPath ID="SiteMapPath2" runat="server">
                </asp:SiteMapPath>
                <br />
                <br />
                <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
                </asp:ContentPlaceHolder>
            </td>
        </tr>
    </table>
</div>
<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" />
</form>

image

       SiteMapPath 控件是完全可以自定义的。与外观相关的属性

ShowToolTips 是否显示鼠标停留时显示的描述性文字
ParentLevelsDisplayed 设置同时显示父节点层数的最大值。默认 -1,显示所有层级。
RenderCurrentNodeAsLink 如果为 true,当前页面的路径会显式为一个可单击的链接。默认为 false
PathDirection 两个选择:RootToCurrent 和 CurrentToRoot 。正序或反序的显示路径的层级
PathSeparator 层级之间的字符,默认为 >

       如果还需要更多控制,可以通过样式和模板重定义 SiteMapPath 控件和 HTML:

样    式

模    板

应  用  于

NodeStyle NodeTemplete 除了根节点和当前节点的所有路径部分
CurrentNodeStyle CurrentNodeTemplete 当前页面的节点
RootNodeStyle RootNodeTemplete 根节点。如果根节点就是当前页面,使用当前页面的模板和样式
PathSeparatorStyle PathSepararorTemplete 每个节点间的分隔符

       下面的 SiteMapPath 使用一个箭头图片做分隔符并把一个加粗的固定字符串作为根节点,当前页面使用斜体:

<asp:SiteMapPath ID="SiteMapPath1" runat="server">
    <PathSeparatorTemplate>
        <asp:Image ID="Image1" runat="server" ImageUrl="~/images/arrow.jpg" />
    </PathSeparatorTemplate>
    <RootNodeTemplate>
        <b>Root</b>
    </RootNodeTemplate>
    <CurrentNodeTemplate>
        <i><asp:Label ID="Label1" runat="server" Text='<%# Eval("title") %>'></asp:Label></i>
    </CurrentNodeTemplate>
</asp:SiteMapPath>

       这里用的数据绑定表达式获取绑定到当前节点的标题属性,同样也可以获取 url 特性和 description 特性。

显示站点地图的一部分

       在目前所有的示例中,页面控件都是完全复制站点地图文件的结构的。不过,这并不一定总是你所期望的。一个大型站点地图可能会分散用户对当前页面相关部分的注意力。此外,太多的层级有可能导致整个树不能够巧妙的加载到页面上。

1. 跳过根节点

       你可能并不喜欢 Home 节点突出的方式,如果要对其进行清理,可以设置 SiteMapDataSource.ShowStartingNode 为 false。如果还是要显示 Home 入口,可以修改站点地图文件让它在页面的第一组里定义 Home 节点。而真正的根节点因为不会显示,所以也不需要任何 URL:

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
  <siteMapNode title="Root" description="Root" >
    <siteMapNode title="Home" description="Root" url="~/Default.aspx"></siteMapNode>
    <siteMapNode title="Products" description="Our products" url="~/Products.aspx" >
      <siteMapNode title="Hardware" description="Hardware choices" url="~/Hardware.aspx" />
  ...    
</siteMap>

image  这个结果可能更漂亮,整个层次少了最外层的一个嵌套(Home)。

2. 从当前节点开始

       另一个方法时从当前节点开始只显示站点地图的一部分。例如,可以用某个控件(如 TreeView)显示从当前节点开始的层次中的所有内容,如果要向上跳,可以结合 SiteMapPath 控件一起使用。

       只需简单的设置 SiteMapDataSource.StartFromCurrentNode 为 true 。SiteMapPath 仍将显示完整的层次结构,因为它不使用 SiteMapDataSource 。仍然可以选择是否用 ShowStartingNode,不过现在它决定是否显示当前节点,因为该节点现在是导航树的起点。

<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" StartFromCurrentNode="true" ShowStartingNode="false" />

image

3. 从指定节点开始

       SiteMapDataSource 还有两个属性可以帮助配置导航树:

StartingNodeUrl:

       它接受应该成为数中第一个节点的 URL (相当于重定义了一个根节点)。不过这个 URL 必须和 Web.sitemap 文件中该节点的 url 特性完全匹配。在几个位数不多的站点地图间切换时,StartingNodeUrl 属性特别有用。最理想的方案是定义多个站点地图文件并绑定到你希望使用的那个文件。遗憾的是,默认的 XmlSiteMapProvider 只支持一个站点地图文件,所以你需要一个不同的机制。遇到这种情况时,解决方法是把不同的站点地图分解到 Web.sitemap 文件的独立分支中

       假设,网站包括零售商和雇员部分。你可以把它们分解成 2 个结构并在同一个文件的不同分支里定义它们

       还可以通过 siteMapFile 特性把一个站点地图文件分解成多个单独的文件,不过即使这样,你还是只有一个站点地图树,并且它总是从 Web.sitemap 文件开始,不过你可以更轻松的管理站点地图了。

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
  <siteMapNode title="Home" description="Root" url="~/Default.aspx" >
    <siteMapNode siteMapFile="Dealers.sitemap" />
    <siteMapNode siteMapFile="Employees.sitemap" />
  </siteMapNode>
</siteMap>

注解:

       因为 XmlSiteMapProvider 不允许重复 URL,所以这项技术的应用会受到很大的限制。虽然可以创建多个等效的 URL 来解决这一问题(例如,结尾处加入查询字符串参数),不过,这会带来更多令人头痛的问题。最好的办法还是设计自己的站点地图提供程序。

StartingNodeOffset:

       它接受一个整数,用来指示 SiteMapDataSource 向下(整数)或向上(负数)移动树的多少层。这个属性的使用有很多需要注意的地方。

       下面的示例可以帮助理解它是如何工作的。假设你在站点的这个地方:

Home > Products > Software > Custom > Contact Us

      如果 SiteMapDataSource 从 Home(默认)节点开始,并且你把 StartingNodeOffset 设置为 2,它将沿着树向下移动 2 级并从那个节点向下绑定这个树。在本示例中,那个节点是 Software:

Software > Custom > Contact Us

       也就是说,你能够跳转到 Software 组或 Custom 组里的任意链接,但除此之外,哪里也去不了。

       如果试图向下移动太多层(例如,用户位于第 2 层,而你提供的数值是 3),SiteMapDataSource 会超出层级,绑定控件会显式为空。

       另一项有用的技术是从当前节点向上移动。例如设置为 -3,那么 SiteMapDataSource 将会从当前页面(Contact Us)向上移动 3 层并绑定到这棵树:

Products > Software > Custom > Contact Us

       这项技术更有用一些,因为它保证了导航控件总是显示相同个数的层级。如果试图超越根节点,将只会看到最大的层级数。

注意:

       确定希望使用的 SiteMapDataSource 正确组合需要做几次尝试。这 2 个属性是很多网站从没有使用的特殊属性。如果站点地图树很复杂,嵌套层次很深,它们就会非常有用。用这些属性可以减少一次显示的层级数。这样的导航链更方便阅读和理解(至少更紧凑,不会浪费宝贵的 Web 页面空间)。

       如果要用 SiteMapPath(它不使用 SiteMapDataSource) 获得同样的效果,可以设置 SiteMapPath.ParentLevelsDisplayed 属性。

站点地图对象

       要显示导航结构,除了使用无代码的数据绑定技术,还可以通过编程和导航信息交互。有 2 个原因会使你这样做:

  • 修改页面的显示。例如,可以获取当前节点的信息并用它配置页头和标题之类的细节。
  • 实现不同的导航逻辑。例如,在新闻阅读器里可能只希望显示当前页面的部分子节点。

       站点地图 API 非常直观。你需要借助 System.Web 命名空间的两个类来使用它。入口点是 SiteMap 类,它提供静态属性 CurrentNode(当前页面的站点地图节点)和 RootNode(根节点地图节点),这 2 个属性都返回 SiteMapNode 对象,你可以获取来自站点地图的信息,包括标题、描述、URL等。

       还可以用当前对象 SiteMapProvider 的方法来查找节点,这些方法可通过 SiteMap.Provider 静态属性获得。例如,SiteMap.Provider.FindSiteMapNode()允许通过 URL 搜索节点。

       SiteMapNode 的导航属性:ParentNode、ChildNodes、PreviousSibling、NextSibling。

       看以下代码,页面上有两个标签,分别显示从当前节点获得的标题和信息:

protected void Page_Load(object sender, EventArgs e)
{
    lblHead.Text = SiteMap.CurrentNode.Title;
    lblDescription.Text = SiteMap.CurrentNode.Description;
}

       下一个示例提供下一个按钮,允许用户遍历整个子节点集:

protected void Page_Load(object sender, EventArgs e)
{
    if (SiteMap.CurrentNode.NextSibling != null)
    {
        lnkNext.NavigateUrl = SiteMap.CurrentNode.NextSibling.Url;
        lnkNext.Visible = true;
    }
    else
    {
        lnkNext.Visible = false;
    }
}
原文地址:https://www.cnblogs.com/SkySoot/p/2739114.html