|
Custom TreeNode Collapser
Published: 10/23/2007 |
|
Here's an interesting little class I threw together (very quickly - use at your own risk, and definitely test it out) to handle a problem with a new enterprise system I am writing. We're using a completely customized TreeView control, and one of the requirements is that top-level nodes be collapsable. That is to say, if you have three nodes in a row, the user should be able to collapse those nodes into one node, and then re-expand them afterwards. I wrote a control that handles this for you, you just pass it the first node in the group and the number of nodes to collapse, and it does the rest.
Here's the class:
VB:
Public Class TreeNodeCollapser
#Region "Module-level Variables"
Private m_clsCollapsedNode As TreeNode
Private m_sCollapsedNodeText As String
Private m_iCollapsedNodeImageIndex As Integer
Private m_iCollapsedNodeSelectedImageIndex As Integer
Private m_clsCollapsedNodes As System.Collections.Generic.List(Of TreeNode)
#End Region
#Region "Class Constructors"
Public Sub New(ByVal CollapsedNodeText As String)
Me.m_sCollapsedNodeText = CollapsedNodeText
End Sub
Public Sub New(ByVal CollapsedNodeText As String, ByVal CollapsedNodeImageIndex As Integer)
Me.New(CollapsedNodeText)
Me.m_iCollapsedNodeImageIndex = CollapsedNodeImageIndex
Me.m_iCollapsedNodeSelectedImageIndex = CollapsedNodeImageIndex
End Sub
Public Sub New(ByVal CollapsedNodeText As String, ByVal CollapsedNodeImageIndex As Integer, ByVal CollapseNodeSelectedImageIndex As Integer)
Me.New(CollapsedNodeText, CollapsedNodeImageIndex)
Me.m_iCollapsedNodeSelectedImageIndex = CollapseNodeSelectedImageIndex
End Sub
#End Region
#Region "Properties"
Public Property CollapsedNodeText() As String
Get
Return m_sCollapsedNodeText
End Get
Set(ByVal value As String)
m_sCollapsedNodeText = value
End Set
End Property
Public Property CollapsedNodeImageIndex() As Integer
Get
Return m_iCollapsedNodeImageIndex
End Get
Set(ByVal value As Integer)
m_iCollapsedNodeImageIndex = value
End Set
End Property
Public Property CollapsedNodeSelectedImageIndex() As Integer
Get
Return m_iCollapsedNodeSelectedImageIndex
End Get
Set(ByVal value As Integer)
m_iCollapsedNodeSelectedImageIndex = value
End Set
End Property
#End Region
Public Function CollapseNodes(ByVal FirstNode As TreeNode, ByVal SubsequentNodeCount As Integer) As TreeNode
' avoid painting...
FirstNode.TreeView.SuspendLayout()
FirstNode.TreeView.BeginUpdate()
' make new node to represent the collapsed group...
m_clsCollapsedNode = New TreeNode(Me.CollapsedNodeText, Me.CollapsedNodeImageIndex, Me.CollapsedNodeSelectedImageIndex)
' store each node to be collapsed locally...
m_clsCollapsedNodes = New List(Of TreeNode)()
Dim clsTemp As TreeNode = FirstNode
Do While Not clsTemp Is Nothing
m_clsCollapsedNodes.Add(clsTemp)
If m_clsCollapsedNodes.Count = SubsequentNodeCount + 1 Then
clsTemp = Nothing
Else
clsTemp = clsTemp.NextNode
End If
Loop
' get node collection...
Dim clsNodes As TreeNodeCollection = Nothing
If Not FirstNode.Parent Is Nothing Then
clsNodes = FirstNode.Parent.Nodes
Else
clsNodes = FirstNode.TreeView.Nodes
End If
' add collapsed node to treeview...
clsNodes.Insert(FirstNode.Index, m_clsCollapsedNode)
' remove other nodes...
For Each clsTemp2 As TreeNode In m_clsCollapsedNodes
clsNodes.Remove(clsTemp2)
Next clsTemp2
' add this item as the tag to the temp node...
m_clsCollapsedNode.Tag = Me
' resume painting...
m_clsCollapsedNode.TreeView.ResumeLayout()
m_clsCollapsedNode.TreeView.EndUpdate()
' return...
Return m_clsCollapsedNode
End Function
Public Sub ExpandNodes()
' validate...
If m_clsCollapsedNode Is Nothing Then
Throw New System.Exception("You cannot call ExpandNodes until you call CollapseNodes.")
End If
' avoid painting...
Me.m_clsCollapsedNode.TreeView.SuspendLayout()
Me.m_clsCollapsedNode.TreeView.BeginUpdate()
' get node collection...
Dim clsNodes As TreeNodeCollection = Nothing
If m_clsCollapsedNode.Parent Is Nothing Then
clsNodes = m_clsCollapsedNode.TreeView.Nodes
Else
clsNodes = m_clsCollapsedNode.Parent.Nodes
End If
' replace all nodes in the treeview...
For Each clsNode As TreeNode In m_clsCollapsedNodes
clsNodes.Insert(m_clsCollapsedNode.Index, clsNode)
Next clsNode
' remove the collapsed node...
clsNodes.Remove(m_clsCollapsedNode)
' resume painting...
clsNodes(0).TreeView.ResumeLayout()
clsNodes(0).TreeView.EndUpdate()
' clear variables...
m_clsCollapsedNode = Nothing
m_clsCollapsedNodes = Nothing
End Sub
End Class
public class TreeNodeCollapser
{
#region Module-level Variables
private TreeNode m_clsCollapsedNode;
private string m_sCollapsedNodeText;
private int m_iCollapsedNodeImageIndex;
private int m_iCollapsedNodeSelectedImageIndex;
private System.Collections.Generic.List<TreeNode> m_clsCollapsedNodes;
#endregion
#region Class Constructors
public TreeNodeCollapser(string CollapsedNodeText)
{
this.m_sCollapsedNodeText = CollapsedNodeText;
}
public TreeNodeCollapser(string CollapsedNodeText, int CollapsedNodeImageIndex)
: this(CollapsedNodeText)
{
this.m_iCollapsedNodeImageIndex = CollapsedNodeImageIndex;
this.m_iCollapsedNodeSelectedImageIndex = CollapsedNodeImageIndex;
}
public TreeNodeCollapser(string CollapsedNodeText, int CollapsedNodeImageIndex, int CollapseNodeSelectedImageIndex)
: this(CollapsedNodeText, CollapsedNodeImageIndex)
{
this.m_iCollapsedNodeSelectedImageIndex = CollapseNodeSelectedImageIndex;
}
#endregion
#region Properties
public string CollapsedNodeText
{
get { return m_sCollapsedNodeText; }
set { m_sCollapsedNodeText = value; }
}
public int CollapsedNodeImageIndex
{
get { return m_iCollapsedNodeImageIndex; }
set { m_iCollapsedNodeImageIndex = value; }
}
public int CollapsedNodeSelectedImageIndex
{
get { return m_iCollapsedNodeSelectedImageIndex; }
set { m_iCollapsedNodeSelectedImageIndex = value; }
}
#endregion
public TreeNode CollapseNodes(TreeNode FirstNode, int SubsequentNodeCount)
{
// avoid painting...
FirstNode.TreeView.SuspendLayout();
FirstNode.TreeView.BeginUpdate();
// make new node to represent the collapsed group...
m_clsCollapsedNode = new TreeNode(this.CollapsedNodeText, this.CollapsedNodeImageIndex, this.CollapsedNodeSelectedImageIndex);
// store each node to be collapsed locally...
m_clsCollapsedNodes = new List<TreeNode>();
TreeNode clsTemp = FirstNode;
while (clsTemp != null)
{
m_clsCollapsedNodes.Add(clsTemp);
if (m_clsCollapsedNodes.Count == SubsequentNodeCount + 1)
clsTemp = null;
else
clsTemp = clsTemp.NextNode;
}
// get node collection...
TreeNodeCollection clsNodes = null;
if (FirstNode.Parent != null)
clsNodes = FirstNode.Parent.Nodes;
else
clsNodes = FirstNode.TreeView.Nodes;
// add collapsed node to treeview...
clsNodes.Insert(FirstNode.Index, m_clsCollapsedNode);
// remove other nodes...
foreach (TreeNode clsTemp2 in m_clsCollapsedNodes)
clsNodes.Remove(clsTemp2);
// add this item as the tag to the temp node...
m_clsCollapsedNode.Tag = this;
// resume painting...
m_clsCollapsedNode.TreeView.ResumeLayout();
m_clsCollapsedNode.TreeView.EndUpdate();
// return...
return m_clsCollapsedNode;
}
public void ExpandNodes()
{
// validate...
if (m_clsCollapsedNode == null) throw new System.Exception("You cannot call ExpandNodes until you call CollapseNodes.");
// avoid painting...
this.m_clsCollapsedNode.TreeView.SuspendLayout();
this.m_clsCollapsedNode.TreeView.BeginUpdate();
// get node collection...
TreeNodeCollection clsNodes = null;
if (m_clsCollapsedNode.Parent == null)
clsNodes = m_clsCollapsedNode.TreeView.Nodes;
else
clsNodes = m_clsCollapsedNode.Parent.Nodes;
// replace all nodes in the treeview...
foreach (TreeNode clsNode in m_clsCollapsedNodes)
{
clsNodes.Insert(m_clsCollapsedNode.Index, clsNode);
}
// remove the collapsed node...
clsNodes.Remove(m_clsCollapsedNode);
// resume painting...
clsNodes[0].TreeView.ResumeLayout();
clsNodes[0].TreeView.EndUpdate();
// clear variables...
m_clsCollapsedNode = null;
m_clsCollapsedNodes = null;
}
}
...and here's how you might use it:
C#:
Public Partial Class frmTestNodeCollapser
Inherits Form
Private m_clsCollapser As TreeNodeCollapser = Nothing
Public Sub New()
InitializeComponent()
Me.tvMain.Nodes.Add("Test 1")
Me.tvMain.Nodes.Add("Test 2")
Me.tvMain.Nodes.Add("Test A")
Me.tvMain.Nodes.Add("Test B")
Me.tvMain.Nodes.Add("Test C")
Me.tvMain.Nodes.Add("Test 3")
Me.tvMain.Nodes.Add("Test 4")
m_clsCollapser = New TreeNodeCollapser("Collapsed Nodes")
End Sub
Private Sub btnCollapse_Click(ByVal sender As Object, ByVal e As EventArgs)
' collapse...
Dim clsTemp As TreeNode = m_clsCollapser.CollapseNodes(Me.tvMain.Nodes(2), 2)
clsTemp.NodeFont = New Font(Me.tvMain.Font, FontStyle.Italic)
' display...
Me.btnCollapse.Enabled = False
Me.btnExpand.Enabled = True
End Sub
Private Sub btnExpand_Click(ByVal sender As Object, ByVal e As EventArgs)
m_clsCollapser.ExpandNodes()
Me.btnExpand.Enabled = False
Me.btnCollapse.Enabled = True
End Sub
End Class
public partial class frmTestNodeCollapser : Form
{
TreeNodeCollapser m_clsCollapser = null;
public frmTestNodeCollapser()
{
InitializeComponent();
this.tvMain.Nodes.Add("Test 1");
this.tvMain.Nodes.Add("Test 2");
this.tvMain.Nodes.Add("Test A");
this.tvMain.Nodes.Add("Test B");
this.tvMain.Nodes.Add("Test C");
this.tvMain.Nodes.Add("Test 3");
this.tvMain.Nodes.Add("Test 4");
m_clsCollapser = new TreeNodeCollapser("Collapsed Nodes");
}
private void btnCollapse_Click(object sender, EventArgs e)
{
// collapse...
TreeNode clsTemp = m_clsCollapser.CollapseNodes(this.tvMain.Nodes[2], 2);
clsTemp.NodeFont = new Font(this.tvMain.Font, FontStyle.Italic);
// display...
this.btnCollapse.Enabled = false;
this.btnExpand.Enabled = true;
}
private void btnExpand_Click(object sender, EventArgs e)
{
m_clsCollapser.ExpandNodes();
this.btnExpand.Enabled = false;
this.btnCollapse.Enabled = true;
}
}
Questions or Comments? .
VB to C# and C# to VB translation provided by Instant C# and Instant VB.