CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Eric Wise

Business & .NET

Telerik Treeview Control

As I had previously posted, the company I'm working for right now has purchased 5 subscriptions to the Telerik Control Suite.  I've had some queries from interested developers asking how I like the controls so far and the answer is that I like them a lot!

Today I'm going to show a brief example of how we are using the treeview control to handle email contacts.  We have an internal only custom mail system that allows users to keep track of contacts and organize them into folders.  Being that folders and contacts are have hierarchical relationships this is the perfect use for the telerik treeview control.  We also wanted to get rid of our old clunky interface and use context menus to give managing contacts a "desktop" feel on the web.

Step 1: HTML view

Here is the html attributes of the treeview control for reference.  You can see how various events and paths have been set for images, context menus, etc.

id="tvwMailContacts" runat="server" OnNodeEdit="HandleNodeEdit" AllowNodeEditing="True" BeforeClientContextClick="ContextMenuClick" ContextMenuContentFile="~/XML/ContextMenus.xml" OnNodeContextClick="HandleContextClick" ImagesBaseDir="~/Images/Outlook/" CausesValidation="False"

Step 2: Setting up the context menus

Every node on the Telerik tree can be assigned to a context menu XML file, the path of which is set in the properties.  Every user may add or delete contacts and folders owned by them, but there are some system level folders that they are not allowed to edit or delete.  So we ended up with three types of context menus defined in xml as follows:

<?xml version="1.0" encoding="utf-8" ?>

<ContextMenus>

   <Menu Name="UserContactFolder">

      <Item Image="drafts.gif" Text="Edit Folder" PostBack="False" />

      <Item Image="newFolder.gif" Text="New Folder" PostBack="True"/>

      <Item Image="contact.gif" Text="New Contact" PostBack="True"/>

      <Item Image="deleteMessage.gif" Text="Delete Folder" PostBack="True"/>

   </Menu>

   <Menu Name="SystemContactFolder">

      <Item Image="newFolder.gif" Text="New Folder" PostBack="True"/>

      <Item Image="contact.gif" Text="New Contact" PostBack="True"/>

   </Menu>

   <Menu Name="UserContact">

      <Item Image="drafts.gif" Text="Edit Contact" PostBack="True" />

      <Item Image="deleteMessage.gif" Text="Delete Contact" PostBack="True"/>

   </Menu>

</ContextMenus>

Notice how ourthree menu types expose different commands and you can even control whether the click causes a postback or not.  Editing a contact causes a postback because there is a few fields for contact information while editing a folder name can happen on the client before it posts back.  We'll get into the code for that later.

Step 3: Populating the treeview

To create the propery hierarchy for the treeview control, we are pulling two DataTables into a dataset, defining a relationship and using the GetChildRows dataset method.  The code to do this is as follows:

First, we walk the rows in the folder table and find the rows where the parentFolder is null, that means they are top level folders.  Once we find a top level folder we create a node and then recursively populate its children, both folders and contacts.

    1         ds.Relations.Add("FolderRelation", ds.Tables(0).Columns("contactFolderID"), ds.Tables(0).Columns("parentFolder"), False)
    2         ds.Relations.Add("ContactRelation", ds.Tables(0).Columns("contactFolderID"), ds.Tables(1).Columns("contactParentFolder"), False)
    3  
    4         Dim dbRow As DataRow
    5         For Each dbRow In ds.Tables(0).Rows
    6             If dbRow.IsNull("parentFolder") Then
    7                 'populate node properties
    8                 Dim node As RadTreeNode = CreateContactNode(dbRow("contactFolderID"), dbRow("FolderName").ToString(), dbRow("folderImage").ToString(), True)
    9  
   10                 'Check to see it this is a user or system folder, or a contact
   11                 If IsDBNull(dbRow("folderOwner")) Then
   12                     node.ContextMenuName = "SystemContactFolder"
   13                 Else
   14                     node.ContextMenuName = "UserContactFolder"
   15                 End If
   16  
   17                 tree.AddNode(node)
   18                 RecursivelyPopulateContactFolders(dbRow, node)
   19                 RecursivelyPopulateContacts(dbRow, node)
   20             End If
   21         Next dbRow

Here is the node creation and recursive logic.  You can see how the context menu name is set matching the XML file:

    1     Private Sub RecursivelyPopulateContactFolders(ByVal dbRow As DataRow, ByVal node As RadTreeNode)
    2         Dim childRow As DataRow
    3         For Each childRow In dbRow.GetChildRows("FolderRelation")
    4             'populate node properties
    5             Dim childNode As RadTreeNode = CreateContactNode(childRow("contactFolderID"), childRow("FolderName").ToString(), childRow("folderImage").ToString(), True)
    6  
    7             'Null owners are system folders
    8             If IsDBNull(childRow("folderOwner")) Then
    9                 childNode.ContextMenuName = "SystemContactFolder"
   10             Else
   11                 childNode.ContextMenuName = "UserContactFolder"
   12             End If
   13  
   14             node.AddNode(childNode)
   15             RecursivelyPopulateContactFolders(childRow, childNode)
   16             RecursivelyPopulateContacts(childRow, childNode)
   17         Next childRow
   18     End Sub
   19  
   20     Private Sub RecursivelyPopulateContacts(ByVal dbRow As DataRow, ByVal node As RadTreeNode)
   21         Dim childRow As DataRow
   22         For Each childRow In dbRow.GetChildRows("ContactRelation")
   23             'populate node properties
   24             Dim childNode As RadTreeNode = CreateContactNode(childRow("emailContactID"), childRow("Alias").ToString(), "contact.gif", False)
   25             childNode.ContextMenuName = "UserContact"
   26  
   27             node.AddNode(childNode)
   28         Next childRow
   29     End Sub
   30  
   31     Private Function CreateContactNode(ByVal ID As Integer, ByVal displayText As String, ByVal nodeImage As String, ByVal expanded As Boolean, Optional ByVal contextMenuName As String = "") As RadTreeNode
   32         Dim node As New RadTreeNode(displayText)
   33         node.Image = nodeImage
   34         node.Expanded = True
   35         node.ID = ID.ToString()
   36         Return node
   37     End Function

The relational data looks like this:

Step 4: Testing Context Menus

We can now fire up the application and use the context menus for the 3 types of items (contact, system folder, and user folder).  Here's a shot of it in action:

Step 5: Client Side Editing

Notice from the telerik control html that we defined a javascript function for to fire on context clicks.  We want to capture the edit folder click and allow them to do a client side edit and then post the edit to the server.  All we have to do is define a javascript function (specified in the telerik html).

function ContextMenuClick(node, itemText) {

   if (itemText == "Edit Folder") {

      node.StartEdit();

   }

   return true;

}

Here's the result:

Step 6: Server Side Code

All of the save/delete/update logic resides on the server in the subroutine specified in the telerik control html.  Here is the code to handle clicks based on their context menu type.  We have one for the postback menu items and one for the edit item.  This is very easy and confortable to do because the NodeEvents argument behaves very similarily to an item command:

    1     Protected Sub HandleContextClick(ByVal sender As Object, ByVal NodeEvents As RadTreeNodeEventArgs)
    2         Try
    3             Dim contextCommand As String = NodeEvents.ContextMenuItemText
    4             Dim currentNode As RadTreeNode = NodeEvents.NodeClicked
    5  
    6             Dim contactFolder As New SchoolOne.Mail.EmailContactFolder
    7             Select Case contextCommand
    8                 Case "Delete Folder"
    9                     If NodeEvents.NodeClicked.Nodes.Count > 0 Then
   10                         Throw New Exception("Can not delete a folder with items in it!")
   11                     End If
   12                     contactFolder.ID = Integer.Parse(NodeEvents.NodeClicked.ID)
   13                     contactFolder = MailDomainManager.Load(contactFolder)
   14                     MailDomainManager.Delete(contactFolder)
   15  
   16                 Case "New Folder"
   17                     contactFolder.Owner = ThisUser.InternalEmail
   18                     contactFolder.Name = "New Folder"
   19                     contactFolder.ParentFolder = Integer.Parse(NodeEvents.NodeClicked.ID)
   20                     contactFolder.Image = "folder.gif"
   21                     contactFolder = MailDomainManager.Save(contactFolder)
   22  
   23                 Case "New Contact"
   24                     ShowControls()
   25                     ParentFolderID.Text = NodeEvents.NodeClicked.ID
   26  
   27                 Case "Edit Contact"
   28                     ShowControls()
   29                     EmailContactID.Text = NodeEvents.NodeClicked.ID
   30                     Dim emailContact As New SchoolOne.Mail.EmailContact(Integer.Parse(EmailContactID.Text))
   31                     emailcontact = MailDomainManager.Load(emailcontact)
   32                     txtContactEmail.Text = emailcontact.EmailAddress
   33                     txtAlias.Text = emailcontact.ContactAlias
   34  
   35                 Case "Delete Contact"
   36                     Dim emailContact As New SchoolOne.Mail.EmailContact(Integer.Parse(NodeEvents.NodeClicked.ID))
   37                     MailDomainManager.Delete(emailContact)
   38             End Select
   39  
   40             LoadContacts(tvwMailContacts)
   41         Catch ex As Exception
   42             WriteException(ex, ExceptionLog.None)
   43         End Try
   44  
   45     End Sub
   46  
   47     Protected Sub HandleNodeEdit(ByVal sender As Object, ByVal NodeEvents As RadTreeNodeEventArgs)
   48         'check if it is a folder or a contact
   49         Try
   50             If NodeEvents.NodeEdited.Image = "folder.gif" Then
   51                 Dim contactFolder As New SchoolOne.Mail.EmailContactFolder
   52                 contactFolder.ID = Integer.Parse(NodeEvents.NodeEdited.ID)
   53                 contactFolder = MailDomainManager.Load(contactFolder)
   54                 contactFolder.Name = NodeEvents.NewText
   55  
   56                 contactFolder = MailDomainManager.Save(contactFolder)
   57             End If
   58  
   59             LoadContacts(tvwMailContacts)
   60         Catch ex As Exception
   61             WriteException(ex, ExceptionLog.None)
   62         End Try
   63     End Sub

 

Conclusion

So far I am very impressed with the ease of configuring and coding in the Treeview control.  I will post more feedback as I get into the next controls: Editor, Spellcheck, and PanelBar.



Comments

Eric Wise said:

Can't help ya with component Art, never used or seen them.
# March 29, 2005 3:10 PM

Z said:

Hi, how do u get the line numbers copy-pasted too? Are you using VS.Net 2005 or can this be done in VS.Net 2003?
# March 30, 2005 6:01 AM

darrell said:

You might want to get in touch with Mark DiGiovanni, he's worked with the Telerik controls before.
# March 30, 2005 6:42 AM

Eric Wise said:

Line numbers I use a utility I found called copyashtml, it's a visual studio plugin.
# March 30, 2005 6:52 AM

satyendra said:

You have not mentioned  how on should redirect to another page  by tree view node

# October 19, 2006 2:09 AM

Malank said:

do you have any idea how to create a tree directory based on your RadTreeView?

# June 25, 2007 6:06 AM

sandeep said:

hey can u tell me how to write in c3 same code

# August 29, 2008 12:53 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add
Check out Devlicio.us!

Our Sponsors

Free Tech Publications