10

我正在處理SharePoint解決方案上的自定義當前(左側)導航。SharePoint自定義當前導航/ PortalSiteMapProvider

我需要的是導航的根目錄是根網站的直接孩子的變體網站。所有這些變體的直屬子網站和頁面都應該是可見的,但不能擴展。只有當前站點的祖先站點應該被擴展......一直到當前站點/頁面。

一個例子......如果我開始http://spsite.ex/variation/site2/subsite2.1/subsite2.1.1/subsite2.1.1.3/page.aspx頁面上我看到...

Site1 
Site2 
    SubSite2.1 
     SubSite2.1.1 
      SubSite2.1.1.1 
      SubSite2.1.1.2 
      SubSite2.1.1.3 
       page.aspx (YOU ARE HERE) 
    SubSite2.2 
    Site2Page1 
    Site2Page2 
Site3 
Site4 
Site5 

如果我然後點擊鏈接的SubSite2.1我應該看到像...

Site1 
Site2 
    SubSite2.1 (YOU ARE HERE) 
     SubSite2.1.1 
    SubSite2.2 
    Site2Page1 
    Site2Page2 
Site3 
Site4 
Site5 

如果我然後導航到http://spsite.ex/variation/site5/subsite5.1/page.aspx我應該看到像...

Site1 
Site2 
Site3 
Site4 
Site5 
    SubSite5.1 
     SubSite5.1.1 
     page.aspx (YOU ARE HERE) 

我寫了a的解決方案,但我覺得這不是我應該感到驕傲的;我給AspMenu一個近似無限的StaticDisplayLevels,然後擴展PortalSiteMapProvider,覆蓋GetChildNode(node)而不是獲取子節點,除了當前網頁的祖先。

+0

您的解決方案是否正常工作? – 2010-04-08 21:20:02

+0

是!我想我正在尋找驗證,我已經理解了我正在做什麼以及我應該怎麼做,或者如果我需要去購買一些錯誤的代碼偏移量:PI意味着接近無限的'StaticDisplayLevels'。 ..如果'PortalSiteMapDataSource'的'StartingNodeOffset'爲0(來自根目錄),我會得到異常...所以它聞起來有點。 – 2010-04-08 21:35:16

+2

這是Sharepoint應該真的允許你使用開箱即用的導航控制,看看它在互聯網上的普遍使用情況 - 可能在2010年後的下一個版本中...... – 2010-06-25 01:10:06

回答

1

@ScottE簡單多了,我覺得我已經成功地複製代碼我用來解決這個問題:

using System; 
using System.Web; 
using Microsoft.SharePoint; 
using Microsoft.SharePoint.Publishing; 
using Microsoft.SharePoint.Publishing.Navigation; 

namespace StackOverflow.SharePoint 
{ 
    public class Question2602537PortalSiteMapProvider : PortalSiteMapProvider 
    { 

     public override SiteMapNodeCollection GetChildNodes(System.Web.SiteMapNode node) 
     { 
      bool expandChildNodes = false; 
      if (SPContext.Current != null) 
      { 
       expandChildNodes = NodeIsAncestorOfCurrentNode(node); 
      } 

      if (expandChildNodes) 
      { 
       return base.GetChildNodes(node); 
      } 
      else 
      { 
       return new SiteMapNodeCollection(); 
      } 
     } 

     private bool NodeIsAncestorOfCurrentNode(System.Web.SiteMapNode node) 
     { 
      bool returnvalue = false; 
      SPSecurity.RunWithElevatedPrivileges(delegate() 
      { 
       using (SPSite thisSite = new SPSite(SPContext.Current.Site.ID)) 
       { 
        using (SPWeb nodeWeb = this.OpenWeb(thisSite, node)) 
        { 
         using (SPWeb currentWeb = this.OpenNavWeb(thisSite)) 
         { 
          returnvalue = this.AncestorDescendantWebs(nodeWeb, currentWeb); 
         } 
        } 
       } 
      }); 
      return returnvalue; 
     } 

     private SPWeb OpenWeb(SPSite thisSite, System.Web.SiteMapNode node) 
     { 
      // need to use Uri objects, as sometimes the node URL contains a query string 
      // but calling OpenWeb(...) with a ? in your URL throws an exception 
      // using Uri.LocalPath removes the Query String 
      Uri siteUri = new Uri(thisSite.Url); 
      Uri nodeUri = new Uri(siteUri, node.Url); 
      return thisSite.OpenWeb(nodeUri.LocalPath.Split(new string[] { "/_" }, StringSplitOptions.RemoveEmptyEntries)[0], false); 
     } 

     private SPWeb OpenNavWeb(SPSite thisSite) 
     { 
      using (SPWeb currentWeb = thisSite.OpenWeb(this.CurrentWeb.ID)) 
      { 
       SPWeb web = currentWeb; 
       PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web); 

       // Loop all the way up the webs until we find the one which doesn't inherit 
       // (there's gotta be a better way of doing this) 
       while (publishingWeb.InheritCurrentNavigation && 
        !web.ID.Equals(thisSite.RootWeb.ID)) 
       { 
        web = web.ParentWeb; 
        publishingWeb = PublishingWeb.GetPublishingWeb(web); 
       } 

       return web; 
      } 
     } 

     private bool AncestorDescendantWebs(SPWeb ancestor, SPWeb descendant) 
     { 
      // check the URLs to determine if descendant is a subweb or ancestor 
      // (there's gotta be a better way...) 
      if ((descendant.ServerRelativeUrl + "/").ToUpper().StartsWith(ancestor.ServerRelativeUrl.ToUpper() + "/")) 
      { 
       return true; 
      } 
      return false; 
     } 

    } 
} 

也許不是最好的解決 ...但一個解決方案。

+0

看着[@PauliØsterø的答案](http://stackoverflow.com/questions/2602537/sharepoint-custom-current-navigation-portalsitemapprovider/4612334#4612334)我想知道如果方法'SiteMap.CurrentNode。可以使用IsEqualToOrDescendantOf(SiteMapNode)'來避免創建如此多的'SPWeb'對象。 – 2011-02-06 04:43:00

0

如果你想做一個自定義編碼的解決方案,你可以創建一個從HierarchicalDataBoundControl繼承的類。將它與您的masterpage/pagelayout中的PortalSiteMapDataSource掛鉤。這將使您完全控制輸出並儘可能優化。

0

什麼是你的代碼看起來像......像一個典型的菜單這個使用標準SiteMapProvider不能比這個

public class SideMenu : Control 
{ 
    private SiteMapNode _rootNode = SiteMap.RootNode; 
    public SiteMapNode RootNode 
    { 
     get { return this._rootNode; } 
     set { this._rootNode = value; } 
    } 

    public SideMenu() 
    { 
     ID = "SideMenu"; 
    } 

    protected override void CreateChildControls() 
    { 
     var div = new HtmlGenericControl("div"); 
     div.Attributes.Add("id", ID); 
     Controls.Add(div); 

     CreateMenuNodes(RootNode, div); 

     base.CreateChildControls(); 
    } 

    protected override void Render(HtmlTextWriter writer) 
    { 
     if (!ChildControlsCreated) 
     { 
      CreateChildControls(); 
     } 

     base.Render(writer); 
    } 

    private void CreateMenuNodes(SiteMapNode node, HtmlGenericControl container) 
    { 
     if (node.HasChildNodes) 
     { 
      var ul = new HtmlGenericControl("ul"); 
      container.Controls.Add(ul); 

      foreach (SiteMapNode child in node.ChildNodes) 
      { 
       var li = new HtmlGenericControl("li"); 
       ul.Controls.Add(li); 

       var a = new HtmlAnchor() 
       { 
        InnerHtml = HttpUtility.HtmlEncode(child.Title), 
        Title = child.Title, 
        HRef = child.Url 
       }; 

       li.Controls.Add(a); 

       if (SiteMap.CurrentNode.IsEqualToOrDescendantOf(child)) 
       { 
        li.Attributes["class"] = "selected"; 

        CreateMenuNodes(child, li); 
       } 
      } 
     } 
    } 
}