Menu Control
<SharePoint:AspMenu ID="GlobalNav" Runat="server"
DataSourceID="GlobalNavDataSource"
Orientation="Horizontal"
StaticDisplayLevels="1"
MaximumDynamicDisplayLevels="1" />
- DataSourceID is probably the most important property here because it specifies the control which will actually provide the hierarchical data for this menu. In this case it points to a control with ID "GlobalNavDataSource"; we'll take a look at this control shortly.
- Orientation here is "Horizontal" and I think this is fairly self-explanatory. The other option being "Vertical" which the left menu is set to.
- StaticDisplayLevels refers to the number of levels of the hierarchy to show in the menu at once. As "1" is specified here, only one level of the hierarchy - the level directly beneath the root - is shown.
- MaximumDynamicDisplayLevels is similar to StaticDisplayLevels but determines the number of levels to show in dynamic fly-outs. "1" is specified here as well which is why the items beneath Web Site 2 are displayed in a fly-out when the mouse moves over the static item representing Web Site 2.
PortalSiteMapDataSource
Now on to the data source which I found by looking for a declaration with ID="GlobalNavDataSource":
<PublishingNavigation:PortalSiteMapDataSource ID="GlobalNavDataSource" Runat="server" SiteMapProvider="CombinedNavSiteMapProvider" ShowStartingNode="false" StartFromCurrentNode="true" StartingNodeOffset="0" TrimNonCurrentTypes="Heading" TreatStartingNodeAsCurrent="true" />
The PortalSiteMapDataSource is a MOSS-specific data source which knows how to retrieve data from a PortalSiteMapProvider object and expose this data according to the ASP.NET hierarchical data source interface. As such, it specifies the name of the provider it wishes to use to retrieve data via the SiteMapProvider property. We'll look more closely at these providers shortly.
- ShowStartingNode affects whether or not the starting node is actually returned by the data source. By specifying "false" here, the menu only receives the items beneath the starting node and does not include this node (in this case the root node). Compare the above screenshot to the one below which was captured after switching ShowStartingNode to "true":
- StartFromCurrentNode affects where the data source starts but things get a little bit interesting here. This property is set to "true" and the current node (i.e. the node representing the item currently being visited) is Web Site - 2. It seems to follow that the data source should start with Web Site - 2 and display the items beneath. However, we've noticed that the menu starts at the root Web site, NavigationExample. So what gives? This is where MOSS navigation starts handling things a little bit differently. By specifying StartFromCurrentNode="true", this is essentially a flag that tells the PortalSiteMapDataSource to apply its own concepts to determine where it should be starting. I'm going to wait until I get to the PortalSiteMapProvider before explaining how this process works, but for now suffice it to say that you should always specify StartFromCurrentNode="true" when using the PortalSiteMapDataSource.
- TrimNonCurrentTypes (and other similar properties below) allows context- and type-based trimming of nodes. By specifying "Heading" here, the data source is being told that it should remove any nodes of type Heading that are not directly beneath the current node. Multiple types may be specified as a comma-delimited list ("Heading, Page, ..."). Allowable types are Area (this indicates Web or Web site), Page, Heading and AuthoredLink.
- TrimNonAncestorTypes (not used in above declaration) will trim out any types specified that are not directly beneath the current site or one of its ancestors.
- TrimNonAncestorDescendantTypes (not used in above declaration) will trim out any nodes of the specified types that are not beneath the current site or one of its ancestor or descendant sites.
- Finally, TreatStartingNodeAsCurrent is directly related to the previous properties, in that it affects which node is treated as the current node for trimming purposes. As noted before, current node by default refers to the node representing the item currently being visited (Web Site - 2 in our continuing example). By setting this property to "true" the data source's starting node is treated as the context or trimming node (NavigationExample in this case). We'll revisit these trimming-related properties later once we've made it a bit further.
PortalSiteMapProvider
The PortalSiteMapProvider object mentioned above is the true source of the hierarchical data and it provides this to the data source. The PortalSiteMapProvider retrieves nodes from WSS's SPNavigation store which provides the ability to create static links and groupings. These items are then merged with the site collection structure (i.e. dynamic items representing Web sites and Web pages) and then security trimming is applied so that users only see items for which they have permission to navigate.
Named providers are declared in the application's web.config file in order to make them widely accessible. The declarations of the two most important PortalSiteMapProviders are shown below (slightly modified for clarity):
<add name="CombinedNavSiteMapProvider" description="CMS provider for Combined navigation" type="Microsoft.SharePoint.Publishing.Navigation.PortalSiteMapProvider" NavigationType="Combined" EncodeOutput="true" /> <add name="CurrentNavSiteMapProvider" description="CMS provider for Current navigation" type="Microsoft.SharePoint.Publishing.Navigation.PortalSiteMapProvider" NavigationType="Current" EncodeOutput="true" />
Note that the name of the first provider, "CombinedNavSiteMapProvider", matches the value specified for the SiteMapProvider property of the data source we examined earlier. From this it becomes clear that the horizontal menu is ultimately supplied by this provider object.