C1TreeView is basically used to display Hierarchical data and can used in both bound and unbound mode. We can even show nested parent-child relationship by implementing C1HierarchicalDataTemplate and this has already been explained in this blog. This blog is an extended version which uses C1HierarchicalDataTemplate and allows end user to search the corresponding TreeView item. To begin with, bind the Treeview control with a DataTable and for that you may again refer to the previous blog mentioned above. After doing so, you have a C1Treeview bound to a self-referential data source. Actual implementation starts now. Objective of the blog is to provide a TextBox to the end user for input and corresponding Node with the input text will be searched in the C1TreeView. The basic concept is to traverse all the nodes of C1TreeView recursively till the search item is found and then, set it as expanded and selected. The searching is done on the basis of the DataRow object associated with the entered text in the DataTable. To do so, you need to handle the TextChanged event of the Textbox and find the associated DataRow in the DataTable . Then, use the ContainerFromIndex method of ItemContainerGenerator Class to get the parent item and check if it matches with the end user input. If it does, then set it selected else call custom SearchItem method in order to traverse its child items.
private void searchtb_TextChanged(object sender, TextChangedEventArgs e)
{
isfound = false;
var val = searchtb.Text;
if (!String.IsNullOrEmpty(val))
{
DataView dv = ds.Tables["data"].DefaultView;
var row = dv.Table.Rows.FirstOrDefault(r => r.ItemArray[2].ToString().StartsWith(val, StringComparison.OrdinalIgnoreCase));
for (int i = 0; i < searchTreeView.Items.Count; i++)
{
//get the parent node
var parentItem = searchTreeView.ItemContainerGenerator.ContainerFromIndex(i) as C1TreeViewItem;
var nodeText = ((C1.Silverlight.Data.DataRowView)(parentItem.Header)).GetData("NodeDescription").ToString();
//check if the search item is the parent node
if (nodeText.StartsWith(val, StringComparison.OrdinalIgnoreCase))
{
if (_last != null)
_last.IsExpanded = false;
parentItem.IsSelected = true;
_last = parentItem;
//set the textbox in focus
searchtb.Focus();
break;
}
else
{
if (isfound == false)
{
//set the previous node to collapse
if (_last != null)
_last.IsExpanded = false;
_last = parentItem;
//expand this node
parentItem.IsExpanded = true;
parentItem.UpdateLayout();
if ((parentItem != null) && (row != null))
//call the custom expand to traverse the child nodes
SearchItem(parentItem, row);
else
parentItem.IsExpanded = false;
}
}
}
}
}
The custom SearchItem method takes C1TreeViewItem and a DataRow object as parameters and runs recursively till the item is found. Here is the code for same:
//custom method for searching the nodes recursively
public void SearchItem(C1TreeViewItem item, DataRow row)
{
if (item != null)
{
//check if it contains the searched item
var childItem = item.ItemContainerGenerator.ContainerFromItem(row.GetRowView() as DataRowView) as C1TreeViewItem;
//if child node is the required node
if (childItem != null)
{
childItem.IsExpanded = true;
childItem.IsSelected = true;
//set the flag to true
isfound = true;
searchtb.Focus();
return;
}
//else expand to next level
else
{
for (int i = 0; i < item.Items.Count; i++)
{
var parentItem = item.ItemContainerGenerator.ContainerFromIndex(i) as C1TreeViewItem;
parentItem.IsExpanded = true;
parentItem.UpdateLayout();
//call this method recursively
SearchItem(parentItem, row);
}
}
}
}