【问题标题】:Dynamically changing the title of a SiteMapNode动态更改 SiteMapNode 的标题
【发布时间】:2009-10-26 12:02:20
【问题描述】:

我们有一个网站使用沼泽标准默认站点地图和安全调整,如下所示:

<siteMap defaultProvider="default" enabled="true">
  <providers>
    <add siteMapFile="~/Web.sitemap" securityTrimmingEnabled="true" name="default" type="System.Web.XmlSiteMapProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
  </providers>
</siteMap>

一切都很好,但是收到了一个请求,要求根据一些后端标准更改一个节点的Title。听起来很简单,但显然不是。

尝试 1 - 处理 SiteMapResolve 事件。 在哪里处理这个事件似乎并不重要,我已经在Global.asax 中展示了它,仅仅是因为那是我尝试过的地方之一并且它有效。

Public Class Global_asax
    Inherits System.Web.HttpApplication

    Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
        AddHandler SiteMap.SiteMapResolve, AddressOf SiteMapResolve
    End Sub

    Sub Application_EndRequest(ByVal sender As Object, ByVal e As EventArgs)
        RemoveHandler SiteMap.SiteMapResolve, AddressOf SiteMapResolve
    End Sub

    Private Shared Function SiteMapResolve(ByVal sender As Object, ByVal e As SiteMapResolveEventArgs) As SiteMapNode

        Dim node As SiteMapNode = SiteMap.CurrentNode
        If IsThisTheNodeToChange(node) Then
            node = node.Clone()
            node.Title = GetNodeTitle()
        End If
        Return node

    End Function

End Class

当导航到相关页面时,这工作正常,但不幸的是,站点导航的一部分涉及一个组合框,该组合框与站点地图数据绑定,如下所示:

<asp:SiteMapDataSource ID="siteMapDataSource" runat="Server" ShowStartingNode="false" StartFromCurrentNode="false" StartingNodeOffset="1" />
<asp:DropDownList ID="pageMenu" runat="Server" AutoPostBack="True" DataSourceID="siteMapDataSource" DataTextField="Title" DataValueField="Url" />

呈现此菜单时,不会为任何内容触发SiteMapResolve 事件,因为当前节点是定义菜单的页面。结果,菜单显示物理站点地图文件中的无意义占位符标题,而不是正确的标题。

尝试 2 - 编写我自己的站点地图提供程序。我不想复制所有默认行为,所以我尝试从默认提供程序派生如下。

Public Class DynamicXmlSiteMapProvider
    Inherits XmlSiteMapProvider

    Private _dataFixedUp As Boolean = False

    Public Overrides Function GetChildNodes(ByVal node As SiteMapNode) As SiteMapNodeCollection

        Dim result As SiteMapNodeCollection = MyBase.GetChildNodes(node)
        If Not _dataFixedUp Then
            For Each childNode As SiteMapNode In result
                FixUpNode(childNode)
            Next
        End If
        Return result

    End Function

    Private Sub FixUpNode(ByVal node As SiteMapNode)

        If IsThisTheNodeToChange(node) Then
            node.ReadOnly = False
            node.Title = GetNodeTitle()
            node.ReadOnly = True
            _dataFixedUp = True
        End If

    End Sub

End Class

这不起作用,因为在浏览网站时,GetChildNodes 似乎并不经常被调用。

尝试 3 - 尝试在数据加载到内存后立即修复数据,而不是在访问时修复。

Public Class DynamicXmlSiteMapProvider
    Inherits XmlSiteMapProvider

    Private _dataFixInProgress As Boolean = False
    Private _dataFixDone As Boolean = False

    Public Overrides Function BuildSiteMap() As SiteMapNode

        Dim result As SiteMapNode = MyBase.BuildSiteMap()
        If Not _dataFixInProgress AndAlso Not _dataFixDone Then
            _dataFixInProgress = True
            For Each childNode As SiteMapNode In result.GetAllNodes()
                FixUpNode(childNode)
            Next
            _dataFixInProgress = False
            _dataFixDone = True
        End If
        Return result

    End Function

    Private Sub FixUpNode(ByVal node As SiteMapNode)

        If IsThisTheNodeToChange(node) Then
            node.ReadOnly = False
            node.Title = GetNodeTitle()
            node.ReadOnly = True
        End If

    End Sub

End Class

这似乎有效。但是,我担心BuildSiteMap 方法中对GetAllNodes 的调用。递归地将所有数据拉入内存以修复一个值对我来说似乎是错误的。此外,我无法控制何时调用 BuildSiteMap。我更喜欢尝试 1 的东西,它在第一次需要节点数据时按需调用。

尝试 4(新) - 类似于尝试 2,但覆盖与读取数据有关的 所有 虚拟成员(CurrentNodeFindSiteMapNode、@987654336 @、GetChildNodesGetCurrentNodeAndHintAncestorNodesGetCurrentNodeAndHintNeighborhoodNodesGetParentNodeGetParentNodeRelativeToCurrentNodeAndHintDownFromParentGetParentNodeRelativeToNodeAndHintDownFromParentHintAncestorNodesHintNeighborhoodNodes),尝试在某处截取动态节点的读取。

这不起作用。我将调试语句放在所有被覆盖的成员中,当数据绑定到下拉列表时,似乎根本没有调用它们。我能想到的唯一解释是,在BuildSiteMap调用期间,所有节点都被一次性读入内存,因此SiteMapNode在枚举子节点时不会碰到提供程序类。

谁有更好的建议?

【问题讨论】:

  • 感谢您的详细提问。它帮助了我遇到的类似案例!

标签: .net asp.net vb.net sitemap sitemapprovider


【解决方案1】:

在我们的自定义 SiteMapProvider 中,我们覆盖 BuildSiteMap 方法并手动构建 SiteMapNodes。要更改和/或添加自定义属性,我们通过创建 NameValueCollection 将自定义属性添加到 SiteMapNodes 并将其添加到 SiteMapNode 构造函数。

【讨论】:

  • 感谢 Mark 的建议,但如果我这样做了,那么我将有效地进行尝试 3,并重新发明轮子。
  • 是的。它不是一个需要重新实现的大轮子,如果您使用自定义构建的菜单或其他组件,它有助于能够添加其他属性。
【解决方案2】:

您已经非常接近尝试 #2 - 您还需要覆盖 GetParentNodeFindSiteMapNode

【讨论】:

  • 雷克斯,恐怕没有任何区别(请参阅我对尝试 4 的编辑)。目前看来尝试 3 是唯一的解决方案。
【解决方案3】:

感谢 Mark 和 Rex 的建议。我最终做的是让站点地图提供者一个人呆着,只修复母版页中的一个节点,因此:

Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init

    ' Do this as early as possible in the page lifecycle so that it happens before any
    ' automatic data binding or control initialisation is done.
    Dim node As SiteMapNode = GetNodeToEdit()
    Dim nodeReadOnly As Boolean = node.ReadOnly
    node.ReadOnly = False
    node.Title = GetNodeTitle()
    node.ReadOnly = nodeReadOnly

End Sub

但是,我接受了 Mark 的回答,因为如果将来需要进行更广泛的修改,我会这样做。

【讨论】:

    【解决方案4】:

    感谢克里斯蒂安的研究。根据您的结果,我提出了以下可能对其他人有所帮助的建议:

    ' Dynamically update some menu items.
    '
    ' Since the correct Medical Center ID is not known until runtime, need to
    ' append "&MEDICAL_CENTER_ID=xxx" to all of the report's URLs in Web.sitemap.
    Public Shared Sub UpdateMenu(ByVal MedicalCenterID As String)
      Dim CurrentNodeTitle As String = ""
      Dim NodeReadOnlyProperty As Boolean
    
      ' Home menu item
      CurrentNodeTitle = SiteMap.CurrentNode.Title
    
      ' Determines if the current node has child nodes.
      If (SiteMap.CurrentNode.HasChildNodes) Then
        ' Loop through top level 1 menu items (looking for Reports)
        For Each ChildNodesEnumerator1 As SiteMapNode In SiteMap.CurrentNode.ChildNodes
          CurrentNodeTitle = ChildNodesEnumerator1.Title
          If CurrentNodeTitle = "Reports" Then
            ' Loop through level 2 menu items (looking for specfic reports)
            For Each ChildNodesEnumerator2 As SiteMapNode In ChildNodesEnumerator1.ChildNodes
              CurrentNodeTitle = ChildNodesEnumerator2.Title
              If CurrentNodeTitle = "Multi-Day Vehicle Requests" Or _
               CurrentNodeTitle = "XXXXXXXXXXXXXXXXX" Then
                ' First check if the URL has not been modified already
                If InStr(ChildNodesEnumerator2.Url, "MEDICAL_CENTER_ID") = 0 Then
                  NodeReadOnlyProperty = ChildNodesEnumerator2.ReadOnly
                  ChildNodesEnumerator2.ReadOnly = False
                  ChildNodesEnumerator2.Url = ChildNodesEnumerator2.Url & "&MEDICAL_CENTER_ID=" & MedicalCenterID
                  ChildNodesEnumerator2.ReadOnly = NodeReadOnlyProperty
                End If
              End If
            Next
          End If
        Next
      End If
    End Sub
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-21
      • 1970-01-01
      • 2020-01-04
      • 2020-04-25
      • 1970-01-01
      • 1970-01-01
      • 2011-12-16
      • 2023-03-21
      相关资源
      最近更新 更多