ShowUsYour<Blog>

Irregular expressions regularly

Using the SiteMapDataSource to display lists of links

Danny Chen just blogged about the SiteMap and showed some interesting ways to make use of custom attributes:

   http://weblogs.asp.net/dannychen/archive/2005/03/28/396099.aspx

There's another one that I'd like to add to this list.  Commonly people are using UL elements to create navigational links because they require less Html to be emitted in the page and are easily styled into nice looking links.  This is the approach that modern applications such as CommunityServer and ProjectDistributor use for their lists of links.  So how would you do that with a SiteMap?  The answer is actually pretty simple because you can bind a SiteMapDataSource directly to a Repeater.

  <ul>
    <asp:Repeater DataSourceId="myDataSource" ...>
      <ItemTemplate>
        <li>
          <a href='<%# Eval("Url") %>'><%# Eval("Title") %></a>
        </li>
      </ItemTemplate>
    </asp:Repeater>
  </ul>

<asp:SiteMapDataSource id="myDataSource" runat="server" ShowStartingNode="false" />

That will give you a nice list of clickable links.

On my site I actually only required a subset of the items in the SiteMap to be rendered on a specific menu.  For example, I had a left navigation menu which only displays a subset of the total items.  In this case I can use the technique that Danny showed off by adding a custom attribute to my SiteMapNode's like so:

  <?xml version="1.0" encoding="utf-8" ?>
  <siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
    <siteMapNode url="Home.aspx" title="Home"  DisplayOnLeft="true">
      <siteMapNode url="Work.aspx" title="Work" />
      <siteMapNode url="School.aspx" title="School" DisplayOnLeft="true" />
    </siteMapNode>
  </siteMap>

So, you can see that 2 of the nodes contain a DisplayOnLeft attribute which is set to true.  Now, to conditionally display those items in my sidebar navigation list I can hook the Repeater's ItemDataBound event and write logic like so...

  SiteMapNode node = e.Item.DataItem as SiteMapNode ;
  string display = node["DisplayOnLeft"];
  if( string.IsEmptyOrNull( display ) || display != "true" ) {
     e.Item.Visible = false ;
  }

Comments

Marcus said:

I´m trying to use this tutorial to create a sitemappath with an unordered list but the repeater only prints the first node. If I use a sitemappath the links shows up as expected. Any idea why it does´t work?

# August 16, 2007 6:12 AM

modi said:

not able to understand ,hence not a good one..i rate it as poor

# October 25, 2007 6:14 AM

Ahmed Hussein said:

to display the rest of nodes in the repeater

<asp:Repeater runat="server" ID="siteMapAsBulletedList" DataSourceID="SiteMapDataSource1">

   <HeaderTemplate>...</HeaderTemplate>

   <ItemTemplate>

       <li>

           <asp:HyperLink runat="server" NavigateUrl='<%# Eval("Url") %>' Text='<%# Eval("Title") %>'></asp:HyperLink>

           <asp:Repeater runat="server" id="SecondLevel" DataSource='<%# CType(Container.DataItem, SiteMapNode).ChildNodes %>'>

               <HeaderTemplate><ul></HeaderTemplate>

               <ItemTemplate>

                   <li>

                       <asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl='<%# Eval("Url") %>' Text='<%# Eval("Title") %>'></asp:HyperLink>

                   </li>

               </ItemTemplate>

               <FooterTemplate></ul></FooterTemplate>

           </asp:Repeater>

       </li>

   </ItemTemplate>

   <FooterTemplate>...</FooterTemplate>

</asp:Repeater>

<asp:SiteMapDataSource ShowStartingNode="false" ID="SiteMapDataSource1" runat="server" />

thanks to  Scott Mitchell  aspnet.4guysfromrolla.com/.../030806-1.aspx

# November 18, 2007 8:04 AM

Vegard said:

For C#, the DataSource property would be set like DataSource='<%# ((SiteMapNode) Container.DataItem).ChildNodes %>'

# July 15, 2008 7:50 AM

Mudu said:

Is there a way to smartly do this recursively? I mean, the classic menu control also displays sub-items...

# September 23, 2008 7:48 AM

Joel @ MMCC said:

Mudu, perhaps, but it would take some pretty advanced coding. If you know in advance how many maximum levels you’ll need, you can simply extend Scott Mitchell’s technique that Ahmed Hussein posted as needed, which requires no code at all unless you count the embedded “DataSource='<%# CType(Container.DataItem, SiteMapNode).ChildNodes %>'>” (for better performance, replace “CType” with “DirectCast” — DirectCast should pretty much ALWAYS be used in place of CType in VB.NET whenever you’re dealing with objects derived from other objects, such as specific Web Controls derived from the generic WebControl or even generic Object).

# January 14, 2009 1:51 PM

yangbing said:

thanks

# February 9, 2010 10:18 PM

Woody said:

This is a good way of latching the menu to do more, I am a bit stuck with how to find other nodes though ?!

# July 29, 2010 9:54 AM

Chris said:

Finally something that works, this will suit my needs perfectly. string.IsEmptyOrNull should be string.IsNullOrEmpty, minor typo I'm sure. Thanks for the info.

# November 9, 2010 2:28 PM

weblogs.asp.net said:

396103.. Not so bad :)

# April 5, 2011 1:27 PM

weblogs.asp.net said:

396103.. Huh, really? :)

# April 30, 2011 10:26 PM

weblogs.asp.net said:

396103.. Peachy :)

# June 14, 2011 1:02 AM

cindy said:

Esto — es insoportable.  

http://eru1.myftp.biz/  

kacie

# August 19, 2011 9:55 AM
Leave a Comment

(required) 

(required) 

(optional)

(required)