10

Sto lavorando a una navigazione corrente (a sinistra) personalizzata su una soluzione SharePoint.SharePoint Navigazione corrente personalizzata/PortalSiteMapProvider

Quello che mi serve è che la radice della navigazione sia una web di variazione, il figlio immediato del web radice. Tutti i siti e le pagine che sono figli immediati di questa variazione dovrebbero essere visibili, sebbene non ampliati. Solo i siti che sono antenati del sito corrente dovrebbero essere espansi ... fino in fondo al sito/pagina corrente.

Un esempio ... se mi metto a pagina http://spsite.ex/variation/site2/subsite2.1/subsite2.1.1/subsite2.1.1.3/page.aspx dovrei vedere ...

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 

Se poi clicco sul link per SubSite2.1 dovrei vedere qualcosa di simile ...

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

Se quindi passare alla http://spsite.ex/variation/site5/subsite5.1/page.aspx dovrei vedere qualcosa di simile ...

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

Ho scritto una soluzione, ma mi sento come se non fosse uno di cui dovrei sentirmi orgoglioso; Ho assegnato a AspMenu un valore quasi-StaticDisplayLevels e successivamente esteso a PortalSiteMapProvider, ignorando GetChildNode(node) a non, ottenere i nodi figlio, ad eccezione degli antenati del Web corrente.

+0

La soluzione funziona? –

+0

Sì! Immagino di essere alla ricerca di una convalida che ho capito cosa sto facendo e come dovrei farlo, o se devo andare a comprare qualche cattivo offset del codice: PI significa "StaticDisplayLevels" quasi inimitabile. .. e se 'PortalSiteMapDataSource' ha un' StartingNodeOffset' di 0 (dalla radice) ottengo eccezioni ... quindi odora un po '. –

+2

Questo è il genere di cose che Sharepoint dovrebbe davvero permettervi di fare con il controllo di navigazione pronto all'uso, vedendo quanto comunemente viene usato su Internet - forse nella prossima versione dopo il 2010 ... –

risposta

1

@ScottE, penso che sono riuscito a riprodurre il codice di ho usato per risolvere questo problema:

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

    } 
} 

Forse non la migliore soluzione ... ma una soluzione.

+0

Guardando [@Pauli Østerø's answer] (http://stackoverflow.com/questions/2602537/sharepoint-custom-current-navigation-portalsitemapprovider/4612334#4612334) Mi chiedo se il metodo 'SiteMap.CurrentNode.IsEqualToOrDescendantOf (SiteMapNode) 'potrebbe essere usato per evitare di creare così tanti oggetti' SPWeb'. –

0

Se si desidera eseguire una soluzione personalizzata codificata, è possibile creare una classe ereditata da HierarchicalDataBoundControl. Collegalo con PortalSiteMapDataSource nella tua pagina master/pagelayout. Questo ti darà il pieno controllo dell'output ed è il più ottimizzato possibile.

0

Che cosa significa il codice assomigliare ... un menù tipico del genere utilizzando le normali SiteMapProvider non può essere reso molto più semplice di questo

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