Thursday, 19 May 2011

Binding link with tree veiw

We've had various feature requests come in for the site navigation feature to include additional built in properties.  This got turned down because it wasn't really useful data about a Site Map Node and because it was easily done through the extensibility features.  In general this will work for any custom attribute but I'll show examples for target since it's the most commonly requested.
First, lets start with a simple web.sitemap and add a custom attributes that we'll want to map to target.  Web.sitemap allows for custom attributes to be added to each SiteMapNode.  They can be accessed later by the indexer property, for example:
Dim someNode As SiteMapNode = GetMyNode()Dim value As String = someNode("value")
 
or
 
SiteMapNode someNode = GetMyNode();string value = someNode["value"];
Here's an example web.sitemap:
 
<?xml version="1.0" encoding="utf-8" ?>
<
siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
  <
siteMapNode url="Home.aspx" title="Home"  target="_blank">
    <
siteMapNode url="Work.aspx" title="Work"  target="_bottom" />
    <
siteMapNode url="School.aspx" title="School"  target="_top" />
  </
siteMapNode>
</
siteMap>

Now add a menu or treeview to the page bound to the SiteMapDataSource.  In order to make this work, we'll subscribe to the Item/Node databound event.



<%@ Page Language="VB" AutoEventWireup="true" 
        
CodeFile="Default.aspx.vb"
        
Inherits="_Default" EnableViewState="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<
html xmlns="http://www.w3.org/1999/xhtml" >
<
head id="Head1" runat="server">    <title>My Page</title>
</
head>
<
body>    <form id="form1" runat="server">        <asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" />        <asp:Menu ID="Menu1" runat="server"
        
DataSourceID="SiteMapDataSource1"      
        
OnMenuItemDataBound="Menu1_MenuItemDataBound">        </asp:Menu>        <asp:TreeView ID="TreeView1" runat="server"
        
DataSourceID="SiteMapDataSource1"
        
OnTreeNodeDataBound="TreeView1_TreeNodeDataBound">        </asp:TreeView>    </form>
</
body>
</
html>

And here is the code that makes it work:
Partial Class Default    Inherits System.Web.UI.Page
    
Protected Sub TreeView1_TreeNodeDataBound(ByVal sender As Object, _
      
ByVal e As System.Web.UI.WebControls.TreeNodeEventArgs) _
      
Handles TreeView1.TreeNodeDataBound

        e.Node.Target =
CType(e.Node.DataItem, SiteMapNode)("target")
    
End Sub
    Protected Sub Menu1_MenuItemDataBound(ByVal sender As Object, _
      
ByVal e As System.Web.UI.WebControls.MenuEventArgs) _
      
Handles Menu1.MenuItemDataBound
        e.Item.Target =
CType(e.Item.DataItem, SiteMapNode)("target")
    
End Sub
End
Class

But what about SiteMapPath?  It's less common that this would want to be done for a SiteMapPath but that doesn't mean we shouldn't able to do it.  Lets see...  Well, it does have an itemDataBound event...
    Protected Sub SiteMapPath1_ItemDataBound(ByVal sender As Object, _
  
ByVal e As System.Web.UI.WebControls.SiteMapNodeItemEventArgs) _
  
Handles SiteMapPath1.ItemDataBound

        
If e.Item.ItemType = SiteMapNodeItemType.Parent Or _
           e.Item.ItemType = SiteMapNodeItemType.Root
Then            If e.Item.Controls(0).GetType().ToString = _
              
"System.Web.UI.WebControls.HyperLink" Then
                CType(e.Item.Controls(0), System.Web.UI.WebControls.HyperLink).Target = _
                 e.Item.SiteMapNode(
"target")
            
End If        End If    End Sub
But it isn't very nice.  There are a lot of things to worry about, is the item a parent or root or is the child control actually a link.  I'm not even checking any of the other possible child controls either.  A much better way to do this would be to use the templating.  Notice the databinding against custom attributes using [key].
    <asp:SiteMapPath ID="SiteMapPath1" runat="server">  <NodeTemplate>    <asp:HyperLink ID="HyperLink1" runat="server"
          
Target='<%# Eval("[target]") %>'
          
NavigateUrl='<%# Eval("url") %>'
          
ToolTip='<%# Eval("description") %>'>             <%#Eval("title")%>
    
</asp:HyperLink>  </NodeTemplate>
</
asp:SiteMapPath>

No comments:

Post a Comment