2009-10-26 29 views
4

我們使用一個沼澤標準的默認地圖與安全修整作爲一個網站如下:的動態調整的SiteMapNode的標題

<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(NEW) - 像嘗試2,但壓倒一切的所有虛擬成員是與讀取數據(CurrentNodeFindSiteMapNodeFindSiteMapNodeFromKeyGetChildNodesGetCurrentNodeAndHintAncestorNodesGetCurrentNodeAndHintNeighborhoodNodesGetParentNodeGetParentNodeRelativeToCurrentNodeAndHintDownFromParentGetParentNodeRelativeToNodeAndHintDownFromParentHintAncestorNodes做,HintNeighborhoodNodes),試圖攔截某處動態節點的讀數。

這沒有奏效。我在所有重寫的成員中都放置了調試語句,並且在數據綁定到下拉列表時,似乎根本沒有人調用它們。我能想到的唯一解釋是節點在調用BuildSiteMap期間一次都被讀入內存,因此在枚舉子節點時SiteMapNode未觸及提供程序類。

有沒有人有更好的建議?

+0

感謝您的詳細質疑。它幫助了我有類似的情況! – danyim 2011-11-03 16:34:12

回答

2

在我們的自定義SiteMapProvider中,我們重寫BuildSiteMap方法並手動構造SiteMapNodes。要更改和/或添加自定義屬性,我們通過創建一個NameValueCollection並將其傳遞給SiteMapNode構造函數來向SiteMapNodes添加自定義屬性。

+0

感謝Mark的建議,但如果我這樣做,那麼我將有效地嘗試3,並重新發明輪子。 – 2009-10-26 14:34:46

+0

是的。它不是重新實現的重要輪子,如果您使用自定義的菜單或其他組件,則它有助於添加其他屬性。 – 2009-10-26 15:16:55

1

您與第2次嘗試非常接近 - 您還需要覆蓋GetParentNodeFindSiteMapNode以及。

+0

雷克斯,這恐怕沒有什麼區別(見我的編輯嘗試4)。目前看起來嘗試3是唯一的解決方案。 – 2009-10-26 14:31:13

1

感謝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 

不過,我已經接受了馬克的回答,因爲這是如果事實證明,我會怎麼做將來需要進行更廣泛的修改。

1

感謝Christian爲您的研究。使用你的結果,我想出了以下可能有助於他人:

' 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