The code demonstrates an example how multiple selection can be implemented in C# using TreeView control.
Initialization
Font boldFont; Font normalFont; List selectedNodes; TreeNode previousNode; public Form1() { selectedNodes = new List(); boldFont = new Font("Arial", 10, FontStyle.Bold); normalFont = new Font("Arial", 10, FontStyle.Regular); InitializeComponent(); }
Build a tree of My Documents folders
private void Form1_Shown(object sender, EventArgs e) { String directory = Environment.GetFolderPath( Environment.SpecialFolder.MyDocuments); BuildTree(directory, null); } private void BuildTree(String directory, TreeNode node) { try { String[] subdirectories = Directory.GetDirectories(directory); foreach (String subdirectory in subdirectories) { String name = Path.GetFileName(subdirectory); TreeNode subnode = (node == null) ? treeView1.Nodes.Add(name) : node.Nodes.Add(name); subnode.NodeFont = boldFont; subnode.Text = subnode.Text; // google: 94354 treenode BuildTree(subdirectory, subnode); } String[] files = Directory.GetFiles(directory); foreach (String file in files) { String name = Path.GetFileName(file); TreeNode subnode = (node == null) ? treeView1.Nodes.Add(name) : node.Nodes.Add(name); subnode.NodeFont = normalFont; subnode.Text = subnode.Text; // google: 94354 treenode } } catch (Exception) { // Ignore exception, e.g. when access to a folder denied } }
Handle node selection
private void treeView1_BeforeSelect(object sender, TreeViewCancelEventArgs e) { // cancel selection, the selection will be handled in MouseDown e.Cancel = true; } private void treeView1_MouseDown(object sender, MouseEventArgs e) { TreeNode currentNode = treeView1.GetNodeAt(e.Location); if (currentNode == null) return; currentNode.BackColor = treeView1.BackColor; currentNode.ForeColor = treeView1.ForeColor; bool control = (ModifierKeys == Keys.Control); bool shift = (ModifierKeys == Keys.Shift); if (control) { // the node clicked with control button pressed: // invert selection of the current node List addedNodes = new List(); List removedNodes = new List(); if (!selectedNodes.Contains(currentNode)) { addedNodes.Add(currentNode); previousNode = currentNode; } else { removedNodes.Add(currentNode); } changeSelection(addedNodes, removedNodes); } else if (shift && previousNode != null) { if (currentNode.Parent == previousNode.Parent) { // the node clicked with shift button pressed: // if current node and previously selected node // belongs to the same parent, // select range of nodes between these two List addedNodes = new List(); List removedNodes = new List(); bool selection = false; bool selectionEnd = false; TreeNodeCollection nodes = null; if (previousNode.Parent == null) { nodes = treeView1.Nodes; } else { nodes = previousNode.Parent.Nodes; } foreach (TreeNode n in nodes) { if (n == currentNode || n == previousNode) { if (selection) { selectionEnd = true; } if (!selection) { selection = true; } } if (selection && !selectedNodes.Contains(n)) { addedNodes.Add(n); } if (selectionEnd) { break; } } if (addedNodes.Count > 0) { changeSelection(addedNodes, removedNodes); } } } else { if (!currentNode.NodeFont.Bold) { // single click: // remove all selected nodes // and add current node List addedNodes = new List(); List removedNodes = new List(); removedNodes.AddRange(selectedNodes); if (removedNodes.Contains(currentNode)) { removedNodes.Remove(currentNode); } else { addedNodes.Add(currentNode); } changeSelection(addedNodes, removedNodes); previousNode = currentNode; } } } protected void changeSelection(List addedNodes, List removedNodes) { foreach (TreeNode n in addedNodes) { if (!n.NodeFont.Bold) { n.BackColor = SystemColors.Highlight; n.ForeColor = SystemColors.HighlightText; selectedNodes.Add(n); } } foreach (TreeNode n in removedNodes) { n.BackColor = treeView1.BackColor; n.ForeColor = treeView1.ForeColor; selectedNodes.Remove(n); } }
Thanks, man. Helped a lot, saved me some time.
I think I know how to improve.
Your test tree is bigger than control that’s why i think U haven’t noticed the exception thrown when there is no TreeNode under your Cursor. Easy to fix:
TreeNode currentNode = treeView1.GetNodeAt(e.Location);
if(currentNode==null)
{…
The second thing is:
You should switch places of iterator cycles in changesSelection. Cause if you dont and try to select, diselect and then to select again a single node you will fail.
LikeLike
Thanks for the code, it is very useful and saves my time in treeview selection.Thanks again 🙂
LikeLike
I have been searching for ages for a solution to giving a treeview multi task. Everywhere else made it out to be sooo much more complicated.
Thank you so much!
LikeLike