Skip to main content
Email Password   helpLost your password?

TreeView2.png Odyssey TreeView3.png

Introduction

OdcTreeView is a templated ASP.NET AJAX Server Control with hierarchical data binding.

This article covers the following topics:

Static Nodes

Like the ASP.NET TreeView, you can either use a data source to retrieve the nodes, or you simply specify them in the ASPX source like this:

<odc:OdcTreeView ID="OdcTreeView1" 
    runat="server" EnableViewState="true"> 
<Nodes>
<odc:OdcTreeNode Text="1">
<odc:OdcTreeNode Text="1.1" ImageUrl="~/ColorHS.png" />
<odc:OdcTreeNode Text="1.2" />
</odc:OdcTreeNode>
<odc:OdcTreeNode Text="2" />
<odc:OdcTreeNode Text="3">
<odc:OdcTreeNode Text="3.1" />
<odc:OdcTreeNode Text="3.2" />
<odc:OdcTreeNode Text="3.3">
<odc:OdcTreeNode Text="3.3.1" />
<odc:OdcTreeNode Text="3.3.2" />
<odc:OdcTreeNode Text="3.3.3" />
<odc:OdcTreeNode Text="3.3.4" ImageUrl="~/ColorHS.png" />
<odc:OdcTreeNode Text="3.3.5" ShowCheckBox="true" />
<odc:OdcTreeNode Text="3.3.6" 
  ShowCheckBox="true" IsChecked="true" />
</odc:OdcTreeNode>
</odc:OdcTreeNode>
<odc:OdcTreeNode Text="4">
<odc:OdcTreeNode Text="4.1" />
<odc:OdcTreeNode Text="4.2" 
  PopulateOnDemand="true" IsExpanded="true" />
<odc:OdcTreeNode Text="4.3" />
<odc:OdcTreeNode Text="4.4" />
<odc:OdcTreeNode Text="4.5" />
</odc:OdcTreeNode>
</Nodes>
</odc:OdcTreeView>

Populate on Demand

In conjunction with static nodes, you can also enable population on demand, which means that you don’t need to declare all possible nodes at once, and add child nodes to a parent node only when the parent expands for the very first time. Therefore, you simply set the PopulateOnDemand property of an OdcTreeNode to true, which causes the OdcTreeView to raise a NodePopulate event. This event can be implemented like so:

protected void OdcTreeView1_NodePopulate(object sender, OdcTreeNodeEventArgs e)
{
    OdcTreeNode node = e.Node;
    node.PopulateOnDemand = false;
    for (int i = 1; i < 6; i++)
    {
        OdcTreeNode sub = new OdcTreeNode();
        sub.Text = node.Text + "." + i.ToString();
        sub.IsExpanded = false;
        sub.PopulateOnDemand = i==3;
        node.ChildNodes.Add(sub);
    }
}

Note that this method also sets the PopulateOnDemand to false, so it will not cause another NodePopulate when the node gets collapsed and later expanded, since it stores it state in the View State together with the populated tree nodes.

Data Binding

Of course, OdcTreeNode also supports data binding with any IHierarchicalDataSource. You can fighter declare a DataSourceID with the name of a DataSource that implements IHierarchicalDataSource, or set the DataSource property to any IHierarchicalDataSource at runtime. Additionally, you need to declare at least one OdcTreeNodeBinding class unless you don’t use a customized node template to bind the embedded controls directly. This class specifies how to bind the properties of a data item with the properties of a OdcTreeNodeItem, or it declares what default values a OdcTeeNodeItem should be assigned to. If you don’t set the OdcTreeNodeBinding.Level to a value, then this binding is used as the template for all nodes. If you specify a level, however, this OdcTreeNodeBinding only affects the nodes that are in this hierarchical level.

This example demonstrates declarative data binding with an XML file:

<odc:OdcTreeView ID="OdcTreeView1" 
  runat="server" DataSourceID="XmlDataSource1">
<TreeNodeBindings>
<odc:OdcTreeNodeBinding Level="0" TextField="Title"/>
<odc:OdcTreeNodeBinding Level="1" TextField="Title" />
<odc:OdcTreeNodeBinding Level="2" TextField="Title" 
  ShowCheckBox="true" IsChecked="true" />
<odc:OdcTreeNodeBinding Level="3" TextField="Value" 
  ShowCheckBox="true" IsChecked="false" />
</TreeNodeBindings>
</odc:OdcTreeView>
<asp:XmlDataSource ID="XmlDataSource1" runat="server" 
  DataFile="~/Xml.xml"></asp:XmlDataSource>

Templates

OdcTreeView knows three different templates:

The following example demonstrates how to use templates:

<odc:OdcTreeView ID="treeView" runat="server" AutoPostBack="False" >
<ContextMenuTemplate>
<asp:LinkButton ID="btnOkay" runat="server" CommandName="ok" Text="Okay" /><br />
<asp:LinkButton ID="btnCancel" runat="server" CommandName="cancel" Text="Cancel" />
</ContextMenuTemplate>
<EditNodeTemplate>
<asp:TextBox runat="server" ID="tbText" Text='<%# Bind("Text") %>' />
<asp:LinkButton ID="btnRename" runat="server" CommandName="rename" Text="Rename" />
<asp:LinkButton ID="btnCancel" runat="server" CommandName="cancel" Text="Cancel" />
</EditNodeTemplate>
<NodeTemplate>
<%# Container.Node.Text %><asp:LinkButton 
  Style="padding-left: 4px" ID="btnAdd" runat="server"
CommandName="add" Text="Add" />
<asp:LinkButton ID="btnRemove" runat="server" CommandName="remove" Text="Remove" />
<asp:LinkButton ID="btnEdit" runat="server" CommandName="edit" Text="Edit" />
</NodeTemplate>
</odc:OdcTreeView>

As you can see, there are two ways used to bind the OdcTreeNode.Text property:

  1. <%# Bind("Text") %>
  2. Using Bind() enables you to access the properties of the data bound item, rather than the OdcTreeNode itself, so this means that the node must be bound to an object that has a Text property. If not data bound, Bind() retrieves the properties from the node itself.

  3. <%# Container.Node.Text %>
  4. This is the usage to access the properties of the tree node directly. Since Container is of type OdcTreeNodeContainer that exposes Node, DataItem would be the data bound object.

OdcTreeNodeBinding also offers a NodeTemplate to specify. This enables you to modify the look of nodes of different levels. The following example demonstrates how to apply a button to the root node:

<odc:OdcTreeView ID="OdcTreeView1" runat="server" DataSourceID="XmlDataSource1">
<TreeNodeBindings>
<odc:OdcTreeNodeBinding Level="0" TextField="Title">
<NodeTemplate>
<asp:Button runat="server" Text="this is the root" UseSubmitBehavior="False" />
</NodeTemplate>
</odc:OdcTreeNodeBinding>
<odc:OdcTreeNodeBinding Level="1" TextField="Title" />
<odc:OdcTreeNodeBinding Level="2" TextField="Title" 
   ShowCheckBox="true" IsChecked="true" />
<odc:OdcTreeNodeBinding Level="3" TextField="Value" 
   ShowCheckBox="true" IsChecked="false" />
</TreeNodeBindings>
</odc:OdcTreeView>

NodeBinding Event

It is even possible to attach any OdcTreeNodeBinding of the NodeBindings collection to a node determined in an event named NodeBinding. This works both for data binding and static nodes, or population on demand. Thus, you can vary the template of a node by using any terms you want.

The following example illustrates how to use NodeBinding:

ASPX part:
<odc:OdcTreeView ID="OdcTreeView1" runat="server" EnableViewState="true" Font-Size="9"
Font-Names="Arial" EnableDragDrop="true" AutoPostBack="false" DisableTextSelection="true"
EnableClientExpand="true" AllowNodeEditing="false" ExpandDepth="7" 
onnodebinding="OdcTreeView1_NodeBinding" 
onnodepopulate="OdcTreeView1_NodePopulate">
<TreeNodeBindings>
<odc:OdcTreeNodeBinding Name="Root" ShowCheckBox="true">
<NodeTemplate>
<asp:Label ID="Label2" isText="true" runat="server" 
   Text="<%# Container.Node.Text %>" />
</NodeTemplate>
</odc:OdcTreeNodeBinding>
</TreeNodeBindings>
Code part:
/// <summary>
/// Determine what OdcTreeNodeBinding to apply for for a node.
/// </summary>
protected void OdcTreeView1_NodeBinding(object sender, 
               Odyssey.Web.TreeView.OdcTreeNodeBindingEventArgs e)
{
OdcTreeNode node = e.Node;
// if the node has child nodes, apply a different NodeBinding
// that contains a different node template to the node:
if (node.HasChildNodes) e.Binding = e.Bindings.GetNamedBinding("Root");
}

AJAX Server Control

OdcTreeView is an AJAX Server Control, which means that it requires a ScriptManager on the page. With AJAX, the tree view can perform many operations directly in the browser without requiring any postback. So, it is possible to select a node, and expand and collapse nodes completely inside the browser. It is even possible to edit the text of a node in the browser if you set AllowNodeEditing to true. The OdcTreeView adds a hidden field to the page, and registers it to the client part of the control. The client uses JavaScript to update the changes to the hidden field, and on a postback, the server side reads the value of the hidden field and updates the values to reflect the changes that were made at the client side. However, if you want to have a postback when a node is selected, edited, expanded, or collapsed, then you must set the AutoPostBack to false. Note that a postback always occurs when a node gets expanded that has PopulateOnDemand set to true.

JavaScript Namespaces, Classes, Properties, and Custom Events

The client part of the OdcTreeView contains of a JavaScript class named TreeViewControl, a TreeNode class, and a TreeContextMenuEventArgs class. All classes belong to the Odyssey.Web namespace. I don’t want to go in to the details of how to make JavaScript look like C# having namespaces, classes, interfaces, properties, and events, since there are a lot of good books that capture that functionality. The TreeViewControl is the client part of the AJAX control. It catches HTML events, and performs the required postbacks depending on what event has been raised. You can also specify the client events for the OdcTreeView that execute not at the server side, but at the client side by calling a JavaScript function. The following events are currently available:

The following snippet illustrates how to use the client events and how to retrieve properties from the AJAX classes:

<odc:OdcTreeView ID="OdcTreeView1" runat="server" EnableViewState="true" 
ClientNodeTextChanged="nodeTextChanged"
ClientNodeExpanded = "expanded"
ClientContextMenuOpening="myContextMenu" 
ClientNodeCollapsed="collapsed"
ClientNodeSelectionChanged="nodeSelected"
 


</form>
<script type="text/javascript">
function expanded(node, e) {
if (node.getText()>="4")
  alert("Expanded: "+node.getText());
}


function collapsed(node, e) {
if (node.getText() >= "4")
  alert("Collapsed: " + node.getText());
}
 

function nodeTextChanged(node, e) {
var txt = node.getText();
var e = document.getElementsByName("custom");
e[0].innerHTML = "changed: "+txt;

}

function nodeSelected(node, e) {
var value = node.get_selected();
if (value) {
//node.setText("OK");
var txt = node.getText();
var e = document.getElementsByName("custom");
e[0].innerHTML = "selected: " + txt;
}
}
 
function myContextMenu(tree, e) {
var cm = e.menuElement;
var node = e.node;
var text = node.getText();
if (node.isFirst()) {
e.set_cancel(true);
alert("no menu for the first item!");
}
if (text == "3.3.1")
  cm.style.backgroundColor = 
     "Red"; else cm.style.backgroundColor = "";
}
</script>
</body>
</html>

Custom Style

Unlike the ASP.NET TreeView which uses inline styles to render a table to look like a tree, OdcTreeView uses the <ul> and <li> tags that natively represent a tree view and completely relies on style sheets to manipulate the look. By default, OdcTreeView uses "odcTreeView" as the base style class which is included as an embedded resource, and contains all the necessary styles for rendering, including background images to be attached, like expand and collapse buttons. If you want to customize the style, you simply need to copy the TreeView.css from the source code, rename all .odcTreeView occurrences with your own class name, add a reference to your style sheet to the page, and set the ClassName property of the OdcTreeView to that name. For the sake of smaller HTML code, OdcTreeView uses very short names for class names of sub elements, like class="ul". You might think that this could lead to collisions with other controls that might decide to use the same short name, but since the style sheet always uses the base class in conjunction with the sub class, this risk is eliminated:

.odcTreeView
{
    clear:both;
    vertical-align:top;
    padding:2px;
}


.odcTreeView .ul
{
    list-style-type: none;
    list-style-image: none;
    list-style-position: outside;
    padding: 0px 0px 0px 20px;
    margin:0px;
}

.odcTreeView .Ln
{
    background-image: url('<%=WebResource("Odyssey.Web.TreeView.images.line.gif")%>');
    background-repeat:repeat-y;
    background-position: 0px 0px;
}

The HTML code would look like this:

<div class="odcTreeView" id="OdcTreeView1" EnableClientExpand="true">
<ul class="ul">
<li class="Mid" key="1"><div class="div">
<span class="Collapse" event="collapse"></span>
<span event="click" class="span" id="OdcTreeView1_K1">
<img src="ColorHS.png" style="border-width:0px;" />
<span isText="true">1</span>

Points of Interest

The source code contains how to create an AJAX server control, how to add client properties and client events to the control, how to read from an IHierarchicalDataSource, how to implement a DataTemplate, and many more.

History

This is the initial release.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralShowCheckbox property not working in NodeBindingEvent.aspx page Pin
mr.vipan.adecco
2:59 30 Sep '09  
GeneralOpera 9 and Firefox 1 / 2 Pin
jrdutton
4:48 9 Sep '09  
Questionjson support [modified] Pin
cparks270
12:27 27 Aug '09  
GeneralLoadViewState Pin
Member 3619091
0:51 29 Jul '09  
GeneralPrinting of this Tree view Pin
PraveenTItu
21:18 30 Jun '09  
QuestionTree Drill Down [modified] Pin
youngaj
7:51 7 May '09  
AnswerRe: Tree Drill Down Pin
youngaj
5:56 21 May '09  
GeneralRetreive control information from node Pin
Un1imit
10:20 22 Apr '09  
QuestionProblem using this control with DataBound in a Master/Content page solution. Pin
jy_p
10:05 21 Apr '09  
AnswerRe: Problem using this control with DataBound in a Master/Content page solution. Pin
Salvor
3:45 19 Jun '09  
GeneralContextMenu??? Pin
Adamant22
12:55 14 Apr '09  
GeneralNodeClick event without postback? Pin
AndyStephens
2:02 14 Apr '09  
AnswerRe: NodeClick event without postback? Pin
jy_p
11:00 21 Apr '09  
QuestionHow to store key information? [modified] Pin
Sven Weiberg
23:48 23 Sep '09  
QuestionVB Version Pin
masterelectric
6:50 16 Mar '09  
Generalis it possible to use ImageButton? Pin
Member 534625
9:17 23 Feb '09  
AnswerRe: is it possible to use ImageButton? Pin
Thomas Gerber
12:37 2 Mar '09  
QuestionHow to add this control in to my toolbox Pin
Member 4076023
1:29 20 Feb '09  
AnswerRe: How to add this control in to my toolbox Pin
Thomas Gerber
5:59 20 Feb '09  
GeneralRe: How to add this control in to my toolbox Pin
Member 4076023
20:14 20 Feb '09  
GeneralRe: How to add this control in to my toolbox Pin
Thomas Gerber
13:55 21 Feb '09  
GeneralCan ClientContextMenuOpening event support in firefox? [modified] Pin
iso90000
22:46 6 Feb '09  
GeneralRe: Can ClientContextMenuOpening event support in firefox? Pin
iso90000
20:12 12 Feb '09  
AnswerRe: Can ClientContextMenuOpening event support in firefox? Pin
Thomas Gerber
2:02 13 Feb '09  
GeneralRe: Can ClientContextMenuOpening event support in firefox? Pin
jrdutton
4:50 9 Sep '09  


Last Updated 7 Dec 2008 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2009