SiteMapNode의 제목을 동적으로 변경합니다
-
06-07-2019 - |
문제
우리는 보안 트리밍과 함께 Bog-Standard Default 사이트 맵을 사용하는 웹 사이트가 있습니다.
<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
이것은 작동하는 것 같습니다. 그러나 나는 전화가 걱정됩니다 GetAllNodes
에서 BuildSiteMap
방법. 하나의 값을 고치기 위해 모든 데이터를 메모리로 재귀 적으로 끌어 당기는 것은 잘못된 것 같습니다. 또한, 나는 언제 통제 할 수 없습니다 BuildSiteMap
호출됩니다. 나는 노드 데이터가 처음 필요할 때 요청에 따라 호출되는 시도 1과 비슷한 것을 선호합니다.
시도 4 (신규) - 시도 2와 같지만 우선적입니다 모두 읽기 데이터와 관련된 가상 회원 (CurrentNode
, FindSiteMapNode
, FindSiteMapNodeFromKey
, GetChildNodes
, GetCurrentNodeAndHintAncestorNodes
, GetCurrentNodeAndHintNeighborhoodNodes
, GetParentNode
, GetParentNodeRelativeToCurrentNodeAndHintDownFromParent
, GetParentNodeRelativeToNodeAndHintDownFromParent
, HintAncestorNodes
, HintNeighborhoodNodes
), 어딘가에 동적 노드의 판독을 가로 채려고 노력하십시오.
이것은 작동하지 않았습니다. 나는 모든 재정의 멤버에게 디버그 진술을했으며, 데이터가 드롭 다운 목록에 바인딩 될 때 전혀 호출되지 않은 것 같습니다. 내가 생각할 수있는 유일한 설명은 노드가 모두 BuildSiteMap
전화를 걸어 SiteMapNode
자식 노드를 열거 할 때 제공자 클래스에 도달하지 않습니다.
누구든지 더 나은 제안이 있습니까?
해결책
사용자 정의 SiteMapprovider에서는 BuildSitemap 메소드를 무시하고 SiteMapNodes를 수동으로 구성합니다. 사용자 정의 속성을 변경 및/또는 추가하기 위해 이름 valuecollection을 작성하여 SiteemapNodes에 사용자 정의 속성을 추가하고이를 SetemapNode 생성자에 추가합니다.
다른 팁
당신은 시도 #2와 매우 가깝습니다 - 당신은 또한 또한 무시할 필요가 있습니다. getparentnode 그리고 FindSitemapNode 또한.
제안에 대해 Mark와 Rex에게 감사드립니다. 내가 한 일은 Siteemap 제공 업체를 내버려두고 마스터 페이지의 하나의 노드를 수정하는 것이 었습니다.
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의 답변을 받아 들였다. 왜냐하면 앞으로 더 광범위한 수정이 필요하다는 것이 밝혀지면 그렇게 할 것입니다.
당신의 연구에 감사드립니다. 당신의 결과를 사용하여, 나는 다른 사람들을 도울 수있는 다음을 생각해 냈습니다.
' 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