A Simple and Dynamic BreadCrumb Web User Control for ASP.NET

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Introduction

The term Breadcrumb comes from the story of Hansel and Gretel. While going through the forest, they left breadcrumbs on the way to remember the route. Many of today’s Web sites today (for example, Yahoo) use this concept. A user surfing the site is inside a forest. Breadcrumbs in Web sites show the path the user has taken to reach the current page. They can also tell the hierarchy of the page inside the site. Some sites depend on the directory structure of the site to form the breadcrumb. It splits the virtual path of the directory and shows each directory as a link in the breadcrumb. Here, I will design a breadcrumb that forms the links dynamically by remembering the path the user has taken. It can also remember the querystring passed to the page on the last visit.

Assumptions

I make some assumptions about the breadcrumb. These assumptions act as the requirements for my breadcrumb. If anybody has a different set of requirements, we can think of enhancing the system.

  1. Each page has a level in the site. This level determines the hierarchy of the page irrespective of the directory structure. The home page is Level 1.
  2. The user always goes from higher-level pages to lower-level pages. For example, the navigation will be 1-2-3 or 1-2-4, but not 1-4-2.
  3. If the user comes back to the higher level from a lower level, we can ignore the lower levels. We are not forming a cycle in the breadcrumb. In other words, there won’t be a breadcrumb in the form 1-2-3-4-2. If such navigation happens, the Breadcrumb will be 1-2.
  4. The breadcrumb will always start with Level 1. If the user directly comes to Level 4 (by using a short cut), the breadcrumb should show 1-4.
  5. The breadcrumb should remember the querystring variables of the page.
  6. Each page declares its name to appear in the breadcrumb.

Design and Implementation

Selection of objects

In the breadcrumb, we need to track the state of the previous pages. In ASP.NET, we have a Session object to keep track of the state. The session object should store the state information of multiple pages. So, it would be better to choose any of the collection classes. According to Assumption 2, the breadcrumb should keep an order based on the level. This made me choose SortedList as my collection. We need to store the name, querystring, and url of the page to create the breadcrumb. A structure by the name of PageCrumb can do it.

Implementation strategy

Our BreadCrumb control accepts the Level and Name of the Page from the container page and creates a PageCrumb object. It can get the url and querystring from the request object. The control modifies the SortedList by comparing the levels of the existing PageCrumb objects in the list. The modification means the removal of all lower-level PageCrumb objects from the list. Once the modification is complete, the control can create the breadcrumb by iterating through the SortedList. The BreadCrumb control contains a label whose Text property can be set as our dynamically created breadcrumb.

The Code

The following structure represents the class that can hold the level, url, and linkName of the page. I also keep the level inside the PageCrumb to make it more meaningful even though it is not required for the implementation.

Public Structure PageCrumb

   Private _level As Short
   Private _url As String
   Private _linkName As String

   //We are setting all the properties at the time of construction

   Public Sub New(ByVal level As Short, ByVal url As String,
          ByVal linkName As String)

      _level = level
      _url = url
      _linkName = linkName
   End Sub

   //We are making all the properties as read-only.
   //We are not expecting it to change once it is set.
   Public ReadOnly Property Level() As Short
   Get
      Return _level
   End Get
   End Property

   Public ReadOnly Property Url() As String
   Get
      Return _url
   End Get
   End Property

   Public ReadOnly Property LinkName() As String
   Get
      Return _linkName
   End Get
   End Property
End Structure

The Vb file of the BreadCrumbControl will contain the following code

Declare the following variables:

'Variable holding the Link name of the page
Private _tailName As String
'Variable holding the level of the page
Private _level As Short
'The pagecrumb object of the current page
Private _pageCrumb As New PageCrumb
'We will use a sorted list as we can use the level as key
Private _crumbList As SortedList

Define the following properties:

'Each page has a level. The page should declare its level
Public Property Level() As Short
' TO DO: We can check for some constraints here
   Get
      Return _level
   End Get
   Set(ByVal Value As Short)
      _level = Value
   End Set
End Property

'Each page needs a meaningful name of it. Let them declare it
Public Property TailName() As String
   ' TO DO: We can check for some constraints here
   Get
      Return _tailName
   End Get
   Set(ByVal Value As String)
      _tailName = Value
   End Set
End Property

Modify the Page_Load event by adding the following code. We are creating the PageCrumb object by using the Request.RawUrl. This RawUrl property also contains querystring information. This information helps us to open the page with the querystring once the user comes back to the page.

Private Sub Page_Load(ByVal sender As System.Object, _
                      ByVal e As System.EventArgs) _
                      Handles MyBase.Load
   'We are not disabling viewstate
   If Not (Page.IsPostBack) Then

   'Minimum level is 1
   If (_level <= 0) Then
      _level = 1
   End If

   'If no friendly name gives Untitled as default
   If (_tailName = "") Then
      _tailName = "Untitled"
   End If

   'Create a Crumb object based on the properties of this page
   _pageCrumb = New PageCrumb(_level, Request.RawUrl, _tailName)

 

'Check that our Crumb is there in the session...if not, create 'and add it...else get it If Session.Item("HASH_OF_CRUMPS") Is Nothing Then crumbList = New SortedList Session.Add("HASH_OF_CRUMPS", _crumbList) Else _crumbList = Session.Item("HASH_OF_CRUMPS") End If 'Now modify the List of the breadcrumb ModifyList() 'Put the breadcrumb from the session of sortlist PutBreadCrumbs() End If End Sub

The following function checks the level of the page. If the level is 1, it removes everything from the list and adds the home link. I assume that the Home page is always the first-level page. If there is nothing in the list, we add the Home page to the list. Please remember our Assumption 4 here. Also note the GlobalMembers.HOME_LINK_PATH. It is a string that represents the Url of the home page.

Private Sub ModifyList()
'Remove all Entries from the list that are higher or equal in level
'because at a level there can be max of 1 entry in the list
RemoveLowerLevelCrumbs()
'If level is 1 set the Crumb as home
If _pageCrumb.Level = 1 Then
   _crumbList.Clear()
   _crumbList.Add(CType(1, Short), New PageCrumb(1, _
                  GlobalMembers.HOME_LINK_PATH, "Home"))
Else
   'If nothing in the list adds the home link first
   If _crumbList.Count = 0 Then
      _crumbList.Add(CType(1, Short), New PageCrumb(1, _
                     GlobalMembers.HOME_LINK_PATH, "Home"))
   End If
   'Now add the present list; also, no other check is required here
   'as we have cleaned up the List at the start of the function
      _crumbList.Add(_level, _pageCrumb)
   End If
End Sub

As per our Assumption 3, the breadcrumb should not create a cycle. The following function removes all lower-level pages from the list.

'Function will remove all the entries from the list that are higher
'than or equal to the present level
Private Sub RemoveLowerLevelCrumbs()

Dim level As Short
Dim removalList As New ArrayList(_crumbList.Count)
For Each level In _crumbList.Keys
   If (level >= _level) Then
      removalList.Add(level)
   End If
   Next
   'Now remove all keys in the list
   For Each level In removalList
      _crumbList.Remove()
   Next
End Sub

Now, we can create the breadcrumb by using the list. I am using > as the separator. Also, the last name in the breadcrumb is not a link because it denotes the current page.

Private Sub PutBreadCrumbs()
Dim linkString As New StringBuilder

   Dim pageCrumb As New PageCrumb
   Dim index As Integer

   For index = 0 To _crumbList.Count - 2
      pageCrumb = _crumbList.GetByIndex)
      linkString.Append(String.Format("<a href = {0} >{1} </a>", _
                        pageCrumb.Url, pageCrumb.LinkName))
      linkString.Append(" > ")
   Next index
   'Add the tail also
   pageCrumb = _crumbList.GetByIndex(index)
      linkString.Append(pageCrumb.LinkName)
      lblTrail.Text = linkString.ToString()

   End Sub

End Class

How to Use This Control

Add this user control to any page on which you need a breadcrumb. Then, set the Level and Name properties of the control. I have attached some sample files showing the usage of the control. They also contain the complete source code of the implementation.

Limitations

The above-described BreadCrumb cannot remember the actions happening on the page during postback. We can expose an additional property of the Object type in the PageCrumb object to do this. The calling page can use this object to store any additional information it needs. But, this requires some coding in the container page, so I avoided it. Somebody else can take a better shot on this. Because we are storing the information in the session, we should be a little careful about the number of levels our Web site will have.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read