Creating Navigation Elements

As we mentioned, there are essentially three elements that you can use to create navigation: postings, channels, and administrative functions. To utilize each of these elements, you'll use the PAPI, accessing the specific objects and properties.

Examine the Objects and Properties Necessary for Navigation

With the exception of administrative functions, all navigation is built with channels or postings. Both channels and postings share common properties for building navigation within your Web site. A list of these properties follows, with a brief explanation of each. Keep in mind that if you closely study the .NET class reference in the CMS documentation, you'll find other properties that may be useful, but the properties listed here are the ones you'll use most frequently.

  • Name: Returns the name of the object. The name of the object is what shows up in the URL when an object is requested.

  • DisplayName: Returns the display name of the object. The display name usually contains a longer, more descriptive title for the object. Most sites use this display name to allow content contributors to specify what text will show up in the navigation. In the case of multilingual sites, the display name is very useful for providing the language-specific description of the channel or posting, since there are some character restrictions in URLs.

  • Url: Returns an unqualified, mode-specific URL to an object. The Url property returns a URL to an object within the context of the current Web Author mode. For example, if the Web Author is in Edit mode (unpublished), a GUID-based URL will be returned with the appropriate query string parameters. If the site is in Live, or Published, mode, the URL will be a friendly URL, like what you're used to seeing.

  • UrlModePublished: Forces CMS to provide a non-GUID-based friendly URL to an object. This allows you to retrieve a Live mode URL even if the user is viewing the site in Edit mode.

  • UrlModeUnpublished: Forces CMS to provide a GUID-based URL to the object in Unpublished mode. Similar to UrlMode Published, UrlModeUnpublished will always provide the unpublished URL to an object regardless of the current Web Author context mode.

  • Parent: Provides a reference to the parent of the object. In either a channel or a posting, the parent property returns a channel item object.

Creating Basic Navigation

Now that you've familiarized yourself with the general design considerations and components of building navigation, let's examine some basic code samples to show you how to use what you've learned. As a start, let's look at basic channel navigation. By basic channel navigation, we're simply referring to getting a collection of channels from the PAPI and creating HTML that a content consumer can click on to navigate through that collection. Looking at Listing 14-1, you can see the basic traversal of a channel within the current channel.

Listing 14-1 Basic channel navigation
 private void createBasicChannelNav(Channel startChannel) {       // Get a collection of channels from the startChannel       ChannelCollection navChannels = startChannel.Channels;       // Make sure we've gotten a collection back       if (navChannels != null)       {             // Create a new anchor link and iterate through each             // channel in the collection             HtmlAnchor navLink;             foreach(Channel navChannel in navChannels)             {                   // For each channel in the collection, create new anchor                   // link and add it to the .NET placeholder control on                   // on our page                   navLink = new HtmlAnchor();                   navLink.InnerText = navChannel.DisplayName;                   navLink.HRef = navChannel.Url;                   BasicChannelNav.Controls.Add(navLink);                   BasicChannelNav.Controls.Add(new LiteralControl("<BR>"));             }       } } 

In this example, you'll notice that we're using the Channel object and the properties listed in Listing 14-1. We first retrieve a collection of channels in the start channel. Then, we iterate through the collection, pulling out the Url and DisplayName properties. We've created an ASPX page with a .NET placeholder control (note: this is not the CMS placeholder control) to hold the HtmlAnchor controls we're creating in our code (we could have also added the control to the page controls collection). In Figure 14-9 you can see the result of this code (the results of all code samples in this section are shown in this figure).

Figure 14-9. Basic channel navigation in an ASPX page


The next example is basic posting navigation. In Listing 14-2, you'll notice the code is very similar to the channel example. We simply get a collection of postings from the pass-in startChannel object and then iterate through the collection

Listing 14-2 Basic posting navigation
 private void createBasicPostingNav(Channel startChannel) {       PostingCollection navPostings = startChannel.Postings;       if (navPostings != null)       {             HtmlAnchor navLink;             foreach(Posting navPosting in navPostings)             {                    navLink = new HtmlAnchor();                    navLink.InnerText = navPosting.DisplayName;                    navLink.HRef = navPosting.Url;                    BasicPostingNav.Controls.Add(navLink);                    BasicPostingNav.Controls.Add(new LiteralControl("<BR>"));             }       } } 

Combining both of the prior examples and using recursion to iterate through a whole hierarchy, Listing 14-3 demonstrates mixed channel and posting navigation. Again, this sample builds on the prior two examples, with the exception of the recursive call.

Listing 14-3 Basic channel and posting navigation

[View full width]

 private void createBasicChannelPostingNav(Channel startChannel, string navIndent) {       // Retrieve a collection of postings and channels       PostingCollection navPostings = startChannel.Postings;       ChannelCollection navChannels = startChannel.Channels;       // Create an anchor link       HtmlAnchor navLink = new HtmlAnchor();       // Write out the link to the start channel and add it       // to the .NET (not CMS) placeholder control       navLink.HRef = startChannel.Url;       navLink.InnerText = startChannel.DisplayName;       // Add an indent before the channel link; this will be additive for       // each recursive call       BasicChannelPostingNav.Controls.Add(new LiteralControl(navIndent));       // Add the link to the .NET placeholder control       BasicChannelPostingNav.Controls.Add(navLink);       BasicChannelPostingNav.Controls.Add(new LiteralControl("<br>"));       // Check to see if we got back a collection of postings       if (navPostings != null)       {             foreach(Posting navPosting in navPostings)             {                   // Write out a link to each posting                   navLink = new HtmlAnchor();                   navLink.InnerText = navPosting.DisplayName;                   navLink.HRef = navPosting.Url;                   // Add an indent to each posting (this will be additive as                   // we call the function recursively)                   BasicChannelPostingNav.Controls.Add(new LiteralControl graphics/ccc.gif("&nbsp;&nbsp;&nbsp;"+navIndent));                   // Add the posting link to the .NET placeholder control                   BasicChannelPostingNav.Controls.Add(navLink);                   BasicChannelPostingNav.Controls.Add(new LiteralControl("<BR>"));             }       }       // Make sure we got back a collection of channels       if (navChannels != null)       {             foreach(Channel subChannel in navChannels)             {                   // For each of the sub channels, call the function recursively                   createBasicChannelPostingNav(subChannel, navIndent+"&nbsp;&nbsp;&nbsp;");             }       } } 

Our last sample is a very simple breadcrumb example. In Listing 14-4, notice that we use the parent property of the Channel object to "walk" up the hierarchy. Each time, we retrieve the appropriate properties from the channel we're working with and then reset the currentLocation variable to the parent of that channel. This function provides a good opportunity to create an overload for this function that accepts a posting instead of a channel; the basics of this function would remain the same, since the parent property of a posting also returns a channelitem. Although this function was implemented using a conditional loop, it could just easily have been implemented using recursion.

Listing 14-4 Basic breadcrumb navigation
 private void createBasicBreadcrumbNav(Channel startChannel) {       // Create a variable to hold the start channel object       Channel myCurrentLocation = startChannel;       // Make sure you're not already at the "root" of your site       if (myCurrentLocation.Guid != myBaseChannel.Guid)       {             HtmlAnchor navLink;             // While you're not at your root create a breadcrumb             while(myCurrentLocation.Guid != myBaseChannel.Guid)             {                   // Create a new anchor link and set the appropriate                   // values                   navLink = new HtmlAnchor();                   navLink.HRef = myCurrentLocation.Url;                   navLink.InnerText = myCurrentLocation.DisplayName;                   // Add your breadcrumb to the .NET placeholder control                   BasicBreadcrumbNav.Controls.AddAt(0,navLink);                   BasicBreadcrumbNav.Controls.AddAt(0,new LiteralControl(" > "));                   // Set the current location to the parent of the                   // current location; we're walking one level up                   myCurrentLocation = myCurrentLocation.Parent;             }             // When the loop exits, create a new anchor object             // and set the appropriate value to the root of your             // breadcrumb             navLink = new HtmlAnchor();             navLink.HRef = myBaseChannel.Url;             navLink.InnerText = myBaseChannel.DisplayName;             BasicBreadcrumbNav.Controls.AddAt(0,navLink);       } } 

BOTS Consulting Navigation Samples

Reviewing basic examples is nice, but it's always better to see the navigation implemented in "real" sites. BOTS is certainly not a very complicated site, but we thought it was useful to share the main and left navigation code as a way of comparing the basic examples to code that had a few exceptions. Both the left and main navigation code was implemented in a user control that was dropped onto a page for ease of reuse.

In Listing 14-5, you'll notice that we're not taking in a value to start the navigation. In the function, BOTS is grabbing a very specific channel and starting with that. They made the assumption that this code would be used only in their site. This isn't a bad technique, but it does tend to limit reuse. As you can see, there aren't any exceptions in this code; it's really just basic channel navigation with some HTML formatting.

Listing 14-5 BOTS Consulting main navigation

[View full width]

 private void createMainNavigation() {       try       {             // Retrieve the main BOTS Consulting channel             Channel NavParentChannel = (Channel)CmsHttpContext. Current.Searches.GetByPath graphics/ccc.gif("/Channels/botsconsulting");             this.GlobalNav.Attributes.Add("width","100%");             TableRow GlobalNavRow = new TableRow();             // Make sure we got the channel back             if (NavParentChannel != null)             {                   // Get the collection of channels in the BOTS Consulting site                   ChannelCollection NavParentSubChannels = NavParentChannel.Channels;                   HtmlAnchor navLink;                   // Iterate through the channels in the site                   foreach(Channel SubChannel in NavParentSubChannels)                   {                         navLink = new HtmlAnchor();                         TableCell newTableCell = new TableCell();                         newTableCell.Attributes.Add("align","center");                         navLink.Style.Add("FONT-WEIGHT","bold");                         navLink.Style.Add("COLOR","gray");                         navLink.HRef = SubChannel.Url;                         navLink.InnerText = SubChannel.DisplayName;                         newTableCell.Controls.Add(navLink);                         GlobalNavRow.Cells.Add(newTableCell);                   }             }             this.GlobalNav.Rows.Add(GlobalNavRow);       }       // Perform some very basic exception "handling"       catch(Exception errException)       {             TableRow GlobalNavRow = new TableRow();             TableCell NavItem = new TableCell();             NavItem.Text = "The following exception occurred: " +errException.Message + graphics/ccc.gif "<br>SOURCE: " + errException.Source;             GlobalNavRow.Cells.Add(NavItem);             this.GlobalNav.Rows.Add(GlobalNavRow);       } } 

In the following listings, we provide various "interesting" sections of the left navigation. The code is somewhat lengthy, so we're listing only certain portions that need to be highlighted.

In Listing 14-6, we've provided the task-based navigation. These few lines of code provide a way to create a new posting based on the Press Release Detail template of the In the Press channel. Notice that there are some conditions wrapped around the link so that a content contributor can't accidentally create a posting with the wrong template or in the wrong channel.

Listing 14-6 Task-based publishing in the Web Author

[View full width]

 // Check to see if the posting is in EDIT mode if ((WebAuthorContext.Current.Mode == WebAuthorContextMode.PresentationUnpublished) &&       (CmsHttpContext.Current.Channel.Name.ToString() == "press") &&       CmsHttpContext.Current.Posting.Template.Name == "Press Release Detail") {       // Get the template and channel object for this posting       Template thisTemplate = CmsHttpContext.Current.Posting.Template;       Channel thisChannel = CmsHttpContext.Current.Channel;       // Create the task link       HtmlAnchor taskPublishingLink = new HtmlAnchor();       // Get a URL to a new posting based on the Press Release Detail template       taskPublishingLink.HRef = WebAuthorContext.Current.GetAuthoringNewUrl(thisTemplate graphics/ccc.gif,thisChannel);       taskPublishingLink.InnerText = "New Press Release";       NewTableCell.Controls.Add(new LiteralControl("<br>"));       // Add the publishing link to the side navigation table cell       NewTableCell.Controls.Add(taskPublishingLink); } 

In Listing 14-7, we're showing how BOTS handles most of the left navigation, including the channels and postings. Notice the special conditions with regard to the default posting and the custom property setting that determines whether to show postings in the left navigation or not. Again, in some cases they want postings to display and in other they don't. In an effort to make the code more flexible, they're examining a custom property on the channel to determine whether postings should be listed.

Listing 14-7 The left navigation logic for BOTS

[View full width]

             private void BuildLeftNavTable(Channel StartChannel)             {                   // Define the necessary variables for creating the nav table                   // and the links                   HtmlAnchor NavigationLink;                   TableRow NewTableRow;                   TableCell NewTableCell;                   Literal TextPlaceholder;                   // Get a collection of channels in the pass-in channel                   ChannelCollection SubChannels = StartChannel.Channels;                   // Check to make sure we got back a collection                   if(SubChannels != null)                   {                         // Iterate through the collection                         foreach(Channel SubChannel in SubChannels)                         {                               // Create a new row, cell and anchor link                               NewTableRow = new TableRow();                               NewTableCell = new TableCell();                               NavigationLink = new HtmlAnchor();                               NavigationLink.HRef = SubChannel.Url;                               // If the channel we're on matches the current channel                               // add bolding to the style                               if (SubChannel.Guid.ToString() == CmsHttpContext.Current graphics/ccc.gif.Channel.Guid.ToString())                               {       NavigationLink.Attributes.Add("style","FONT-WEIGHT: Bold; COLOR: gray");                               }                               else                               {       NavigationLink.Attributes.Add("style","COLOR: gray");                               }                               NavigationLink.InnerText = SubChannel.DisplayName;                               NewTableCell.Controls.Add (NavigationLink);                               // If the channel we're on matches the current channel                               // determine whether we need to display postings                               if (SubChannel.Guid.ToString() == CmsHttpContext.Current graphics/ccc.gif.Channel.Guid.ToString())                               {                                     // Only display postings if we're not on the default graphics/ccc.gif posting                                     // or the custom property ShowPostingsOnDefault is set graphics/ccc.gif to true       if((CmsHttpContext.Current.Posting.Name.ToString()!= "default") ||       ((CustomProperty)SubChannel.CustomProperties ["ShowPostingsOnDefault"]).Value graphics/ccc.gif.ToString() == "True")                                     {                                           TextPlaceholder = new Literal();                                           TextPlaceholder.Text="</UL>";       NewTableCell.Controls.Add(TextPlaceholder);                                           // Call the show postings function       ShowPostingsInChannel(SubChannel,NewTableCell);                                           TextPlaceholder = new Literal();                                           TextPlaceholder.Text="</UL>"       NewTableCell.Controls.Add(TextPlaceholder);                                     }                               }                               NewTableRow.Cells.Add(NewTableCell);                               this.LeftNav.Rows.Add(NewTableRow);                         }                   }                   NewTableCell = new TableCell();                   TextPlaceholder = new Literal();                   TextPlaceholder.Text = "<hr color='gray' size='1' width='100%'>";                   NewTableCell.Controls.Add(TextPlaceholder);                   NewTableRow = new TableRow();                   NewTableRow.Cells.Add(NewTableCell);                   this.LeftNav.Rows.Add(NewTableRow);             }             private void ShowPostingsInChannel(Channel CurrentChannel, TableCell graphics/ccc.gif PostingTableCell)             {                   Literal TextPlaceholder;                   HtmlAnchor NavigationLink;                   foreach(Posting SubPosting in CurrentChannel. Postings)                         {                               if(SubPosting.Name.ToLower() != "default")                               {                                     TextPlaceholder = new Literal();                                     TextPlaceholder.Text = "<br>";                                     NavigationLink = new HtmlAnchor();                                     // If the posting we're on is the current posting                                     // then add bolding to the style                                     if(SubPosting.Guid.ToString() == CmsHttpContext graphics/ccc.gif.Current.Posting.Guid.ToString())                                     {       NavigationLink.Attributes.Add("style","FONT-WEIGHT: bold; COLOR: gray");                                     }                                     else                                     {       NavigationLink.Attributes.Add("style","COLOR: gray");                                     }                                     NavigationLink.HRef = SubPosting.Url;                                     NavigationLink.InnerText = SubPosting.DisplayName;       PostingTableCell.Controls.Add(NavigationLink);       PostingTableCell.Controls.Add(TextPlaceholder);                               }                         }             } 

It is a little more complex than the main navigation, but still uses the concepts we demonstrated in the basic navigation samples. In addition, it accounts for the unique situations within the BOTS site.

Microsoft Content Management Server 2002. A Complete Guide
Microsoft Content Management Server 2002: A Complete Guide
ISBN: 0321194446
EAN: 2147483647
Year: 2003
Pages: 298 © 2008-2017.
If you may any questions please contact us: