I would like to know if there is any method to sort (A-Z) a specific node of a TreeView.
The node I want to order is the node "Node1 \ z"
To display it like this:
H N Y Z
Thank you
I would like to know if there is any method to sort (A-Z) a specific node of a TreeView.
The node I want to order is the node "Node1 \ z"
To display it like this:
H N Y Z
Thank you
Your question is how to apply an alpha sort (A-Z) to a specific single node in a TreeView
.
There are many ways to do this and the comments mention some good ones. Here is a solution that efficiently locates the target node using its fully-qualified path in the tree hierarchy. If found, it applies an individualized sort method (specified at runtime) to its children. But first, it must ensure that the TreeView
will permit such reordering by setting its Sorted
property to false
. An advantage of this approach is that it avoids making a call the Sort
method for the entire TreeView
because that would add an unnecessary layer of complexity.
Find the target node
Given a rule for the TreeView
that the fully-qualified path to any node (for example, @"Node1\z"
) is unique, the target can be obtained very efficiently by making an extension for TreeView
that returns the specified node (or null
if not found).
public static TreeNode Find(this TreeView treeView, string path)
{
var parse = path.Split('\\');
var nodes = treeView.Nodes;
TreeNode node = null;
foreach (var text in parse)
{
node = nodes.Cast<TreeNode>().FirstOrDefault(node => node.Text == text);
if (node == null) break;
nodes = node.Nodes;
}
return node;
}
Sort children of target node
This extension for TreeNode
sorts its children according to the comparer Func
passed in as an argument.
public static void Sort(
this TreeNode node,
Func<TreeNode, TreeNode, int> sorter)
{
// Make sure the TreeView will allow reordering
if (node.TreeView != null)
{
node.TreeView.Sorted = false;
}
// Copy the nodes to a list
var list = node.Nodes.Cast<TreeNode>().ToList();
// Sort the list however the `Sorter` says to.
list.Sort((a, b) => sorter(a, b));
// Clear the 'old' order
node.Nodes.Clear();
// Install the 'new' order
foreach (var sorted in list)
{
node.Nodes.Add(sorted);
}
}
Complete method to sort (A-Z) a specific node of a TreeView.
So, to answer the question Is there any method to sort a specific node of a TreeView from A-Z let's say we manufacture such a method by making an extension for TreeView
that does just that. For the path
argument specify the entire hierarchal path like @"Node1"
or @"Node1\z"
.
public static bool SortIfNodeFound(
this TreeView treeView,
string path,
Func<TreeNode, TreeNode, int> sorter)
{
var node = treeView.Find(path);
node?.Sort(sorter);
return node != null;
}
Once you call the TreeView.Sort
method, you actually apply the sorted TREEVIEWSTATE
through the setter of the hidden Sorted
property. The control by that sorts all the nodes using the default sorter, the ascending alphabetical sort. Any attempts afterwards to sort the nodes in a different way fail. You'll note that nothing happens when you remove, sort, and reinsert child nodes of a specific node because once you insert them, the default sorter will interfere and revert your different sort. Again, all the mentioned is when you call the .Sort
method before any other sorting routines.
To override this behavior, you need to provide a custom node sorter for the TreeView.TreeViewNodeSorter
property. An example that allows you to sort the tree or children of node in ascending or descending orders.
public class TreeNodeComparer : IComparer
{
public TreeNodeComparer(SortOrder sortOrder = SortOrder.Ascending) : base()
{
SortOrder = sortOrder;
}
public int Compare(object x, object y)
{
var xn = x as TreeNode;
var yn = y as TreeNode;
switch (SortOrder)
{
case SortOrder.Descending:
return string.Compare(xn.Text, yn.Text) * -1;
case SortOrder.Ascending:
return string.Compare(xn.Text, yn.Text);
default:
return 1;
}
}
public SortOrder SortOrder { get; set; } = SortOrder.Ascending;
}
Note return 1;
here in case SortOrder.None
is necessary to not revert sorting the child nodes of a specific node.
A couple of extension methods for the TreeView
and TreeNode
types.
public static class TreeViewExtensions
{
public static void Sort(this TreeView self, SortOrder order = SortOrder.Ascending)
{
self.TreeViewNodeSorter = new TreeNodeComparer(order);
self.Sort();
}
public static void Sort(this TreeNode self, SortOrder order = SortOrder.Ascending)
{
List<TreeNode> tmp;
TreeView tv = self.TreeView;
if (order == SortOrder.Descending)
tmp = self.Nodes.Cast<TreeNode>().OrderByDescending(n => n.Text).ToList();
else
tmp = self.Nodes.Cast<TreeNode>().OrderBy(n => n.Text).ToList();
var sorter = tv.TreeViewNodeSorter as TreeNodeComparer ?? new TreeNodeComparer();
sorter.SortOrder = SortOrder.None;
tv.TreeViewNodeSorter = sorter;
tv.BeginUpdate();
self.Nodes.Clear();
self.Nodes.AddRange(tmp.ToArray());
tv.EndUpdate();
}
}
You can call them as follows:
// To sort the whole thing...
YourTreeView.Sort(SortOrder.Descending);
// Or the children of the selected node for example...
YourTreeView.SelectedNode.Sort(SortOrder.Ascending);