Mark Wilson I am the creator of TopXML. I am available for international and local (Australia) contracts. I am a Solution Architect/Business Analyst. I have worked in IT in several countries (NZ, Australia, South Africa, UK) building and training teams for government and very large non-governmental organizations. I am ex-Microsoft Consulting Services. I wrote the first book on Microsoft XML published in 2000 called XML Programming with VB and ASP. Most recently I have been building tools for the SEO industry. Ask me for a 37 point SEO health-checkup for your website.
First posted :
03/24/2008
Times viewed :
1148
TreeView with XML Data Binding
Since XML data binding does not involve creating every
tree node “by hand” we no longer can customize the style of each node by
setting properties on the TreeNode objects. However, since the two
representations, TreeNode object and <treenode> tag, should be equivalent
each TreeNode property has to have an XML representation. And indeed, every
TreeNode property that customizes the appearance of a node corresponds to an
attribute of the <treenode> tag with the same name. The table below shows
the relations between the properties of the TreeNode class and the attributes
that customize the appearance. Please study the table to learn more about the
many options available to customize the appearance of the nodes.
1.1
Table 17.4: We can customize a TreeNode either
programmatically through properties of through attributes in the XML data
source. The various customization options control appearance and behavior of
the node.
Property
Attribute
Description
bool CheckBox { get; set }
CHECKBOX
Sets
or retrieves a value that indicates whether to display a check box next to
the nodes in a tree.
bool Checked { get; set }
CHECKED
Sets
or retrieves a value that indicates whether or not the node is checked.
string ChildType { get; set }
CHILDTYPE
Sets
or retrieves the type of TreeNodeType to use for all descendents.
CssCollection DefaultStyle
{ get; set }
DEFAULTSTYLE
Sets
or retrieves a value that indicates the default style for the element.
ExpandableValue
Expandable { get; set }
EXPANDABLE
Sets
or retrieves a value that indicates whether a plus-sign image displays on a
node.
Possible
Values are:
bool Expanded { get; set }
EXPANDED
Sets
or retrieves a value that indicates whether or not the node is expanded.
string ExpandedImageUrl
{ get; set }
EXPANDEDIMAGEURL
Sets
or retrieves the URL of an image to use for expanded nodes.
CssCollection
HoverStyle { get; set }
HOVERSTYLE
Sets
or retrieves a value that indicates the style of the element when the user
hovers the keyboard focus or mouse pointer over it.
string ID { get; set }
ID
Sets
or retrieves a value that indicates the string that identifies the object.
string ImageUrl { get; set }
IMAGEURL
Sets
or retrieves a value that indicates the URL of the image to be displayed on a
node or toolbar item.
string NavigateUrl
{ get; set }
NAVIGATEURL
Sets
or retrieves the URL of the page to navigate to when the user clicks a node.
string NodeData { get; set }
NodeData
Sets
or retrieves a custom data System.String.
TreeNodeCollection
Nodes { get; }
N/A
Retrieves
the TreeNodeCollection of nodes in the control.
object Parent { get }
N/A
Retrieves
the parent object of a node.
TreeView ParentTreeView
{ get; set }
N/A
string SelectedImageUrl
{ get; set }
SELECTEDIMAGEURL
Sets
or retrieves the URL of an image to use for a selected node or TAB.
CssCollection SelectedStyle
{ get; set }
SELECTEDSTYLE
Sets
or retrieves a value that indicates the style for the selected element.
string Target { get; set }
TARGET
Sets
or retrieves a value that indicates the window or frame at which to target
the contents.
string Text { get; set }
Text
string TreeNodeSrc
{ get; set }
TREENODESRC
Sets
or retrieves a value that indicates the URL of an Extensible Markup Language
(XML) file, System.String, or XML data island containing TreeNode
elements.
string TreeNodeXsltSrc
{ get; set }
TREENODEXSLTSRC
Sets
or retrieves the URL to an Extensible Stylesheet Language Transformations
(XSLT) file to transform TreeNode elements.
string Type { get; set }
TYPE
Sets
or retrieves the name of the node type.
The Tree View Web Control offers more customization options than
the properties on the TreeNode class to change the look of the tree. There are
also several properties other properties on the TreeView class where we can select
if we want lines to connect the TreeNodes, roll-over effects, tooltips and a
slew of other options. Setting these properties works just like it did with the
TreeNode class. We can access them in code if we build the tree “by hand” or
specify them as attributes on the <treenode> element in the ASP.NET file.
The table above lists all of theses properties/attributes.
Both techniques we discussed to build a Tree View tree share the
same weakness: They populate the full tree from the top-level to the last leaf
node. That is very inefficient if we do not display the fully expanded tree
because we send data about nodes the user can not access. In fact, the user
probably never expands all nodes of a Tree View. By sending all these nodes we
are slowing down both, download time for the page and render time once the
browser received the page. The download speed may not be as important to you if
you know your user base is connected to your server through a fast LAN
connection, yet even those users benefit from reduced rendering efforts because
of the slow, JavaScript based rendering of this control.
If your application does not display the fully expanded tree
right away then we can improve the performance of the Tree View quite a bit, if
we only transmit the visible nodes. Take the Tree View on the MSDN web site, it
behaves just like that. The Tree View in the Windows Explorer behaves like
that, too. They display only the first level nodes initially and then load the
data for the node you expanded on demand. We can program the Tree View Web
Control to work just like that – with either one of the techniques presented so
far. We focus on XML data binding in this section of this chapter, but setting
up the Tree View programmatically is straight forward after you understood the
concept of delay loading the tree.
Let me show you how we can delay load a Tree View by developing
a new version of the previous example. The Tree View in that example displayed
order and order details we read from a database. This time we start out by
populating only the top level of tree nodes, the order nodes in this example.
With XML data binding can do this by binding to an XML document with only one
level of <treenode> elements.
In our example we supply an XML source document where the
<Order> elements contain no <OrderItem> children, but we could have
ignored the <OrderItem>s in the XSLT stylesheet that transforms the data
document into <treenode>s. You see there is nothing new to the data
binding part. What we have not done yet is handle the user’s interaction with
the Tree View. For the delayed node loading we need to know when the user
clicked on the little plus sign in the tree to expand a node, but there is already
the first problem: By default there is no little plus sign for nodes without
children. Since we explicitly excluded all child nodes we have to force a plus
sign by setting each <treenode>’s EXPANDABLE attribute to “Always” or
“CheckOnce”. stylesheet takes care of that and always adds this attribute when
it transforms <Order> elements to <treenode>s. A transformed
<Order> element could look like this fragment:
Next we need to wire up the Tree View control to receive
notifications when a user actually clicks on the plus sign. The TreeView
control exposes the four Events shown in the table below to handle user
interaction. One of them is the Expanded event, which fires when the user
clicks on the plus icon to expand a node. Other events fire when the user
collapses a node, changes a node’s check box or selects a tree node.
1.2
Table 17.5: The TreeView control fires these events when the
user interacts with the control. We can programmatically bind methods to handle
the events or we can declare the handler methods through the corresponding
attribute on the <treeview> tag.
Fires
when the user changes the selected TreeNode on the TreeView.
To let a TreeView Web Control send notifications for these event
we set the control’AutoPostBack property to true. Finally, we need to specify
which method to call in response to an event. ASP.NET Web Control in that
respect work just like any other .NET class: We bind a delegate to an event
handler method to an Event that the control exposes – even though the event
originates in a web browser and travels across the network to reach the handler
method. Now let’s code the new Page_Load method for the page with the Tree
View:
TreeView1.Expand +=
new ClickEventHandler( TreeView_Expand );
}
Note that we only need to initialize the tree nodes very first
time this page loads. If the page re-loads because of a user event the
IsPostBack property returns true and we do not execute the code under the if
statement. Nevertheless the Tree View keeps its state because it was
transmitted back to the page together with the event notification. The Event
handler on the other hand needs to get registered every time the page loads
because it is not saved in the ViewState.
Now we have everything in place but the actual method handling
an Expand event. Let’s take a minute and think about what the handler needs to
do before we start coding. First, it needs to figure out on which node the
event originated, because that node needs to show its children on the returned
page. Finding which node sent the event is very easy with the two parameters
ASP.NET passes to the event handler method. The first parameter contains a
reference to the TreeView, the second one a special arguments object of type
TreeViewClickEventArgs that contains the index of the node where the event
occurred. Put the two together and call
the GetNodeFromIndex() method on the TreeView with the Node property of the
arguments object and you get the source of the event, as you can see in the
next code snippet:
Next the handler method
needs to add the child nodes to the node. This works just like it did with the
node’s parent, the TreeView class. The TreeNode class also exposes a
TreeNodesCollection property as well as TreeNodeSrc and TreeNodeXsltSrc
properties to either add the children programmatically or to enable XML data
binding respectively.
But where are the child nodes coming from? In order to display
them we first need to load their source data from that database again. In our
example, the handler needs to know the order id of the expanded node to load
the order detail data, but how do we get that id? Well, the TreeNode class
exposes a special property named NodeData to solve this kind of problem. We can
store a string in the property when we create the node and retrieve it later
when we handle an event from that node. Of course, we can also set the NodeData
from an attribute in the XML source. If you go back to REFERENCE, you see that
I stored the order id in the NodeData attribute. Now the event handler can
retrieve the order id from the NodeData property to load the data from the database.
Problem solved – almost, we still have to create the node’s children, but that
is easy not because we can just bind the XML data to the TreeNode as shown in
the code fragment below. XML data binding on a TreeNode also requires calling
the Databind() method on the TreeNode to apply the XSLT transformation to the
XML data source and convert it into a hierarchy of TreeNode objects.
orderNode.Databind(); //
need that so the children are added
The last step in the event handler is to make sure the node
displays the newly added child nodes by setting the node’s Expanded property to
true.
nodeOrder.Expanded =
true;
That is the whole TreeNode_Expanded event handler
implementation. These seven lines can improve the responsiveness of the
TreeView quite substantially. However, there is one important aspect to
consider when it comes to designing pages with the TreeView Web Control. This
example stores the tree data in the page’s ViewState to simplify processing of
user events. This impacts the
performance negatively in two ways. First, the TreeView contains the data about
the TreeView twice, as XML embedded in the <treeview> tag for the browser
to render and in the ViewState for the browser to post back. Second, the
browser posts the whole tree back to the server where ASP.NET deserializes the
ViewState into an object graph. Users on a slow network connection pay the
penalty for the ViewState twice, at first when the HTML page downloads and
again each time they interact with the TreeView. For those users a TreeView
could perform much faster if the TreeView would rebuild the tree on the Server
instead of relying on the ViewState to keep the page state.
I strongly recommend you run some tests with a bandwidth
simulator to determine which approach delivers the best performance to your
target audience. You may find out that you can deliver better performing Tree
View controls by caching the XML source data and the the state of the tree on
the web server instead of posting back kilobytes worth of tree data with each
user event.
1.3
Table 17.6: TreeNode Methods
Method
Description
object Clone()
Creates
a new object that is a copy of the current instance.
void Databind()
Binds
the data to the TreeNode or the TreeView whether the TreeNode has been
expanded or not.
object FindNodeAttribute( string attributeName )
Retrieves
the attribute from the first place it is defined. The attribute may be
defined in the TreeNode, in the TreeNodeType, or in the TreeView.
string GetNodeIndex()
Retrieves
an x.y.z format node index System.String representing the node's position in
the hierarchy.
TreeNodeCollection GetSiblingNodeCollection()
Retrieves
the TreeNodeCollection containing the current TreeNode.
void Remove()
Removes
the TreeNode and any children from its parent's nodes collection.
string ToString()
Retrieves
a System.String that indicates the current object.
I would like to conclude the discussion of the Tree View Web
Control by mentioning some of the useful features we did not talk about. None
of them directly relate to XML, therefore we did not present them in this
section.
There are, for example, a variety of options to customize the
look and feel of the TreeView. You can customize fly-over effects, tool tips,
node icons and check boxes, for example. You can set all these properties
individually, or you can group settings that apply to multiple nodes in a
TreeNodeType and reference that type from a TreeNode.
You can also completely program the TreeView from client-side
JavaScript once you sent it down to the browser. Thus you avoid any post backs
to the server and deliver a solution with very fast responses to user
interactions. Obviously all these features are material for a pure ASP.NET or a
JavaScript book, not one .NET and XML, but you see there is still a lot more to
explore about the TreeView. The documentation on MSDN provides a number of
examples demonstrating how to work with TreeNodeTypes, how to display tree
nodes with images and much, much more.