Removing Nodes from a SiteMapNodeCollection in ASP.NET

Managing the navigation of your ASP.NET application is crucial for providing an optimal user experience. However, there may be instances when you want to exclude certain pages from appearing in your site’s navigation, such as a registration form. If you’re using a Repeater to list child nodes of a SiteMap, you might wonder how to effectively remove specific nodes without running into issues like the NotSupportedException indicating that the collection is read-only. This blog will guide you through a solution to this problem.

Understanding the Problem

In ASP.NET, the SiteMapNodeCollection is often utilized to represent the structure of your website’s pages. This structure can be especially helpful when binding data to a control like a Repeater. However, if you want to hide specific pages, such as a registration form, from your navigation list, simply trying to Remove them from the collection can lead to errors since SiteMapNodeCollection is read-only.

Here’s a quick overview of the scenario:

Example Situation:

  • Control Type: Repeater
  • Data Source: SiteMapNodeCollection from web.sitemap
  • Goal: Exclude the registration page (/Registration.aspx) from the list of displayed pages.

The Challenge

Using the Remove() method on a SiteMapNodeCollection leads to the following error:

NotSupportedException: “Collection is read-only”.

The Solution

To exclude specific nodes effectively, you don’t actually need to modify the original SiteMapNodeCollection. Instead, you can query the collection and create a new enumerable that only contains the nodes you want to display. Here’s how to accomplish this using LINQ.

Step-by-Step Approach

  1. Query the Child Nodes: Use LINQ to filter out the unwanted nodes from the ChildNodes collection.
  2. Select the Desired Nodes: Create a new collection that excludes the registration page.
  3. Bind the New Collection: Set the DataSource of your Repeater to the new collection.

Sample Code Implementation

Here’s the recommended VB.NET code to achieve the desired result:

Dim children = From n In SiteMap.CurrentNode.ChildNodes.Cast(Of SiteMapNode)()
               Where n.Url <> "/Registration.aspx"
               Select n

RepeaterSubordinatePages.DataSource = children
RepeaterSubordinatePages.DataBind() ' Remember to bind the Repeater

Breakdown of the Code:

  • Query: The code uses a LINQ query to filter out the nodes where the URL is equal to /Registration.aspx.
  • Casting: Cast(Of SiteMapNode)() is critical as it allows LINQ to recognize the collection as a set of SiteMapNode objects.
  • Binding: After filtering, the resultant children collection is then set as the DataSource for the Repeater, and DataBind() is called to update the control.

Conclusion

By utilizing LINQ to filter out specific nodes from the SiteMapNodeCollection, you can avoid the pitfalls of trying to modify a read-only collection. This approach not only keeps your code clean and efficient but also ensures that your navigation only displays the pages you deem necessary.

Don’t forget, maintaining a clear and concise navigation structure is an integral component of the user experience on your site. Happy coding!