10

Je travaille sur une navigation personnalisée (à gauche) sur une solution SharePoint. Ce dont j'ai besoin c'est que la racine de la navigation soit un web de variation, l'enfant immédiat du web racine. Tous les sites et les pages qui sont les enfants immédiats de cette variation doivent être visibles, mais pas développés. Seuls les sites qui sont les ancêtres du site actuel doivent être étendus ... jusqu'au site/page actuel.SharePoint Current Current Navigation/PortalSiteMapProvider

Un exemple ... si je commence à la page http://spsite.ex/variation/site2/subsite2.1/subsite2.1.1/subsite2.1.1.3/page.aspx Je vois ...

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 

Si je puis cliquez sur le lien pour SubSite2.1 je devrais voir quelque chose comme ...

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

Si je navigue alors http://spsite.ex/variation/site5/subsite5.1/page.aspx je devrais voir quelque chose comme ...

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

J'ai écrit une solution, mais je pense que ce n'est pas un dont je devrais être fier; J'ai donné le AspMenu un proche-infini StaticDisplayLevels puis étendu PortalSiteMapProvider, en remplaçant GetChildNode(node) à pas obtenir des nœuds enfants, sauf pour les ancêtres du Web actuel.

+0

Votre solution fonctionne-t-elle? –

+0

Yup! Je suppose que je suis en train de chercher la validation que j'ai compris ce que je fais et comment je devrais le faire, ou si j'ai besoin d'acheter de mauvais décalages de code: PI signifie, presque-inifinite 'StaticDisplayLevels'. .. et si le 'PortalSiteMapDataSource' a un' StartingNodeOffset' de 0 (de la racine) j'obtiens des exceptions ... donc ça sent un peu. –

+2

C'est le genre de chose que Sharepoint devrait vraiment vous permettre de faire avec le contrôle de navigation prêt à l'emploi, vu comment il est couramment utilisé sur Internet - peut-être dans la prochaine version après 2010 ... –

Répondre

1

@ScottE, je pense que je suis parvenu à reproduire le code Je l'habitude de résoudre ce problème:

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; 
     } 

    } 
} 

peut-être pas la meilleure solution... mais une solution.

+0

En regardant la réponse de [@Pauli Østerø] (http://stackoverflow.com/questions/2602537/sharepoint-custom-current-navigation-portalsitemapprovider/4612334#4612334) Je me demande si la méthode 'SiteMap.CurrentNode.IsEqualToOrDescendantOf (SiteMapNode) 'pourrait être utilisé pour éviter de créer autant d'objets' SPWeb'. –

0

Si vous souhaitez créer une solution codée personnalisée, vous pouvez créer une classe héritant de HierarchicalDataBoundControl. Connectez-le avec PortalSiteMapDataSource dans votre masterpage/pagelayout. Cela vous donnera un contrôle total de la sortie et est aussi optimisé que possible.

0

A quoi ressemble votre code comme ... un menu typique comme celui-ci en utilisant la norme SiteMapProvider ne peut pas être beaucoup plus simple que ce

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); 
       } 
      } 
     } 
    } 
} 
Questions connexes