LIDOR SYSTEMS

Advanced User Interface Controls and Components

Load Data on Demand from XML File in TreeView .NET

Created: 01 September 2013

If we have large data set, loading of entire data and creation of tree structure will take some time. To avoid this and increase overall performance of our application, we can load data on demand and update the tree structure whenever a new data is needed. Usually for TreeView control the best way to do this is by updating the tree structure whenever a node expands.

TreeView Load on Demand from XML files
Download Sample - TreeView Load on Demand

IntegralUI TreeView has a feature which enables you to load data on demand from/to XML files, memory streams or databases. There is a built-in serialization consisting of several public methods which you can use and create your own solution.

In this article we are going to explain how to use LoadOnDemand method to add child nodes to currently expanding node. For demonstration purposes we have added also an animated gif which is shown whenever the node expands for the first time. The animation lasts for 750 miliseconds, but you can change it if a loading time is longer. In our case the loading is instant, and the animation is not required, we are using it only for demonstration.

We are using a pre-built XML file called tree.xml, which has a tree structure where each node has Key property set to some unique value. We are using this value to easily locate a specific node and load a partial data from the XML file. There is no restriction on which property you can use in your solution, for example you can also use Tag or TagString properties.

At first because we are going to load data whenever a node is expanded, we need to handle the BeforeExpand event.

private void treeView1_BeforeExpand(object sender, LidorSystems.IntegralUI.ObjectCancelEventArgs e)

{

if (!supressCallback && e.Object is LidorSystems.IntegralUI.Lists.TreeNode)

{

LidorSystems.IntegralUI.Lists.TreeNode node = (LidorSystems.IntegralUI.Lists.TreeNode)e.Object;

 

// Load the content only once, when node is expanded for the first time

if (String.IsNullOrEmpty(node.TagString))

{

node.AllowImageAnimation = true;

 

// Start and enable the loading timer which will run the animation

if (!loadTimer.Enabled)

{

loadTimer.Start();

loadTimer.Enabled = true;

}

}

}

}

Private Sub treeView1_BeforeExpand(ByVal sender As Object, ByVal e As LidorSystems.IntegralUI.ObjectCancelEventArgs) Handles treeView1.BeforeExpand

If Not supressCallback AndAlso TypeOf e.[Object] Is LidorSystems.IntegralUI.Lists.TreeNode Then

Dim node As LidorSystems.IntegralUI.Lists.TreeNode = DirectCast(e.[Object], LidorSystems.IntegralUI.Lists.TreeNode)

 

' Load the content only once, when node is expanded for the first time

If [String].IsNullOrEmpty(node.TagString) Then

node.AllowImageAnimation = True

 

' Start and enable the loading timer which will run the animation

If Not loadTimer.Enabled Then

loadTimer.Start()

loadTimer.Enabled = True

End If

End If

End If

End Sub

Because we will show animation prior data is loaded, we will add code which will start the loading timer and animation. After animation completes, we can add the code which will load data from a XML file.

// Suspend the control layout from updating to increase performance

this.treeView1.SuspendUpdate();

 

// Load child nodes and add them to the selected node

TreeViewSerializer serializer = new TreeViewSerializer();

if (System.IO.File.Exists(@fileName))

serializer.LoadOnDemand(this.treeView1, fileName, this.treeView1.SelectedNode, "Key", this.treeView1.SelectedNode.Key);

 

// Mark that this node has completed load process

this.treeView1.SelectedNode.TagString = "LOAD_COMPLETED";

 

// Resume the layout calculations and update the control

this.treeView1.ResumeUpdate();

' Suspend the control layout from updating to increase performance

Me.treeView1.SuspendUpdate()

 

' Load child nodes and add them to the selected node

Dim serializer As New TreeViewSerializer()

If System.IO.File.Exists(fileName) Then

serializer.LoadOnDemand(Me.treeView1, fileName, Me.treeView1.SelectedNode, "Key", Me.treeView1.SelectedNode.Key)

End If

 

' Mark that this node has completed load process

Me.treeView1.SelectedNode.TagString = "LOAD_COMPLETED"

 

' Resume the layout calculations and update the control

Me.treeView1.ResumeUpdate()

In code above we are creating an object that will read the content of XML file and apply it to the currently selected node. The method searches through XML file content for a node that matches the value of Key property with the one of currently selected node. If a node is found, we will extract all child nodes from the XML file and add them to the selected node.

We also need to make sure that the node is expanded, and child nodes are shown. But also we need to avoid calling the BeforeExpand event for the second time for this node. This is done by suppressing the event from firing by using a variable supressCallback.

// After content is loaded, expand the node and make sure it doesn't trigger the BeforeExpand event

supressCallback = true;

this.treeView1.SelectedNode.Expand();

supressCallback = false;

' After content is loaded, expand the node and make sure it doesn't trigger the BeforeExpand event

supressCallback = True

Me.treeView1.SelectedNode.Expand()

supressCallback = False

When all this is completed we can end the loading timer and animation and remove the animated gif from the node.

// If animation is running, stop it and remove the animated gif from the node

isAnimationActive = false;

this.treeView1.StopAnimation(this.treeView1.SelectedNode);

this.treeView1.SelectedNode.SelectedImage = null;

 

// Stop the loading timer

if (loadTimer.Enabled)

{

loadTimerValue = 0;

loadTimer.Enabled = false;

loadTimer.Stop();

}

' If animation is running, stop it and remove the animated gif from the node

isAnimationActive = False

Me.treeView1.StopAnimation(Me.treeView1.SelectedNode)

Me.treeView1.SelectedNode.SelectedImage = Nothing

 

' Stop the loading timer

If loadTimer.Enabled Then

loadTimerValue = 0

loadTimer.Enabled = False

loadTimer.[Stop]()

End If

To better represent the change when node is expanded or collapsed, we are also using a different image. To do this we are handling the AfterExpand and AfterCollapse events, where we change the node image to show open folder image whenever a node is expanded, and close folder image whenever a node is collapsed.

private void treeView1_AfterExpand(object sender, LidorSystems.IntegralUI.ObjectEventArgs e)

{

// Change the icon of the node to show opened folder after node gets expanded

if (e.Object is LidorSystems.IntegralUI.Lists.TreeNode)

{

LidorSystems.IntegralUI.Lists.TreeNode node = (LidorSystems.IntegralUI.Lists.TreeNode)e.Object;

node.ImageIndex = 1;

node.SelectedImageIndex = 1;

}

}

 

private void treeView1_AfterCollapse(object sender, LidorSystems.IntegralUI.ObjectEventArgs e)

{

// Change the icon of the node to show closed folder after node gets expanded

if (e.Object is LidorSystems.IntegralUI.Lists.TreeNode)

{

LidorSystems.IntegralUI.Lists.TreeNode node = (LidorSystems.IntegralUI.Lists.TreeNode)e.Object;

node.ImageIndex = 0;

node.SelectedImageIndex = 0;

}

}

Private Sub treeView1_AfterExpand(ByVal sender As Object, ByVal e As LidorSystems.IntegralUI.ObjectEventArgs) Handles treeView1.AfterExpand

' Change the icon of the node to show opened folder after node gets expanded

If TypeOf e.[Object] Is LidorSystems.IntegralUI.Lists.TreeNode Then

Dim node As LidorSystems.IntegralUI.Lists.TreeNode = DirectCast(e.[Object], LidorSystems.IntegralUI.Lists.TreeNode)

node.ImageIndex = 1

node.SelectedImageIndex = 1

End If

End Sub

 

Private Sub treeView1_AfterCollapse(ByVal sender As Object, ByVal e As LidorSystems.IntegralUI.ObjectEventArgs) Handles treeView1.AfterCollapse

' Change the icon of the node to show closed folder after node gets expanded

If TypeOf e.[Object] Is LidorSystems.IntegralUI.Lists.TreeNode Then

Dim node As LidorSystems.IntegralUI.Lists.TreeNode = DirectCast(e.[Object], LidorSystems.IntegralUI.Lists.TreeNode)

node.ImageIndex = 0

node.SelectedImageIndex = 0

End If

End Sub

Related: Show Different Image on Expand in TreeView

A sample project in C# and VB showing how to load data on demand from XML files is available for download from here: TreeView Load On Demand

Did you Like this Article?


Enter your e-mail address below and you will receive latest articles as well as news on upcoming events and special offers.