Allow multi-select in a .NET TreeView
Solution 1
We did this in a WTL project once, but the basic work needed is the same for .NET. To achieve a multiple selection tree control, you will need to draw the tree items yourself and override the keyboard and mouse handling. You will also need to maintain your own list of items that are selected.
Don't forget to consider selection rules (are parents and children allowed, for example), and don't forget to implement the keyboard shortcuts including selection using Ctrl, Shift, and Ctrl+Shift, as well as the Spacebar for selecting/deselecting.
Solution 2
Solution 3
Are check-boxes an option? or do you want the select like you get in a list box?
- checkboxes are built in
- select like you get in a list box requires a custom tree control
There is a multi-select tree control available on CodeProject:Multi-Select Tree View
Solution 4
The simplest solution would be to extend the existing TreeView control shipped with the framework and override the OnBeforeSelect and OnAfterSelect methods with logic to capture multiple selections.
An example can be found here: http://www.arstdesign.com/articles/treeviewms.html
Solution 5
The below code will allow you to adjust the background colour you use, to ensure that all selected nodes are highlighted.
protected override void WndProc(ref Message m)
{
switch (m.Msg) {
// WM_REFLECT is added because WM_NOTIFY is normally sent just
// to the parent window, but Windows.Form will reflect it back
// to us, MFC-style.
case Win32.WM_REFLECT + Win32.WM_NOTIFY: {
Win32.NMHDR nmhdr = (Win32.NMHDR)m.GetLParam(typeof(Win32.NMHDR));
switch((int)nmhdr.code) {
case Win32.NM_CUSTOMDRAW:
base.WndProc(ref m);
Win32.NMTVCUSTOMDRAW nmTvDraw = (Win32.NMTVCUSTOMDRAW)m.GetLParam(typeof(Win32.NMTVCUSTOMDRAW));
switch (nmTvDraw.nmcd.dwDrawStage) {
case Win32.CDDS_ITEMPREPAINT:
// Find the node being painted.
TreeNode n = TreeNode.FromHandle(this, nmTvDraw.nmcd.lItemlParam);
if (allSelected.Contains(n))
// Override its background colour.
nmTvDraw.clrTextBk = ColorTranslator.ToWin32(SystemColors.Highlight);
m.Result = (IntPtr)Win32.CDRF_DODEFAULT; // Continue rest of painting as normal
break;
}
Marshal.StructureToPtr(nmTvDraw, m.LParam, false); // copy changes back
return;
}
break;
}
}
base.WndProc(ref m);
}
// WM_NOTIFY notification message header.
[System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
public class NMHDR
{
private IntPtr hwndFrom;
public IntPtr idFrom;
public uint code;
}
[StructLayout(LayoutKind.Sequential)]
public struct NMCUSTOMDRAW
{
public NMHDR hdr;
public int dwDrawStage;
public IntPtr hdc;
public RECT rc;
public IntPtr dwItemSpec;
public int uItemState;
public IntPtr lItemlParam;
}
[StructLayout(LayoutKind.Sequential)]
public struct NMTVCUSTOMDRAW
{
public NMCUSTOMDRAW nmcd;
public int clrText;
public int clrTextBk;
public int iLevel;
}
public const int CDIS_SELECTED = 0x0001;
public const int CDIS_FOCUS = 0x0010;
public const int CDDS_PREPAINT = 0x00000001;
public const int CDDS_POSTPAINT = 0x00000002;
public const int CDDS_PREERASE = 0x00000003;
public const int CDDS_POSTERASE = 0x00000004;
public const int CDDS_ITEM = 0x00010000; // item specific
public const int CDDS_ITEMPREPAINT = (CDDS_ITEM | CDDS_PREPAINT);
public const int CDDS_ITEMPOSTPAINT = (CDDS_ITEM | CDDS_POSTPAINT);
public const int CDDS_ITEMPREERASE = (CDDS_ITEM | CDDS_PREERASE);
public const int CDDS_ITEMPOSTERASE = (CDDS_ITEM | CDDS_POSTERASE);
public const int CDDS_SUBITEM = 0x00020000;
public const int CDRF_DODEFAULT = 0x00000000;
public const int CDRF_NOTIFYITEMDRAW = 0x00000020;
public const int CDRF_NOTIFYSUBITEMDRAW = 0x00000020; // flags are the same, we can distinguish by context
public const int WM_USER = 0x0400;
public const int WM_NOTIFY = 0x4E;
public const int WM_REFLECT = WM_USER + 0x1C00;
Related videos on Youtube
Hello all
A developer for a software company in Waterloo, ON. My current project is building development tools (notably an IDE built on Eclipse) for a proprietary language you've never heard of. It makes things interesting. I've done quite a bit of Java and C# development and a smattering of C/C++. At home I get to mess with stuff like Python, Ubuntu and Android development. I'm also part of the local Agile/Lean software community, LoCo contact for Ubuntu Canada and I'm involved in running Kwartzlab, the local hackerspace.
Updated on August 19, 2020Comments
-
Hello all over 3 years
I'm stuck in .NET 2.0 Windows Forms.
It doesn't look like the ability to select multiple nodes exists in the standard
TreeView
control.I'm trying to do this for a context menu selection. So check boxes aren't an acceptable UI paradigm here.
What's the best way to provide that very necessary functionality?
-
Hello all over 15 yearsThat's not really what I'm looking for. Every other tree view in Windows allows you to ctrl-click select multiple entries. And driving a context menu off of checky boxes doesn't make any sense.
-
John Rudy over 15 yearsI can't find an example of a ctrl-click tree view anywhere in the "standard" Windows OS environment. Can you provide an example? I agree that a context menu from checks isn't very sensible, but I don't think expecting users to ctrl+click is either. (A lot of users have trouble with that, in my exp.)
-
Admin over 15 yearsFor the standard Windows Forms treeview, that's how you select more than one node in the tree.
-
Hello all over 15 yearsOkay, "standard" may be the wrong word. Take, for example, the Solution Explorer in Visual Studio.
-
Admin over 15 yearsThe problem is that the "standard" controls you get to play with and use for free (the ones that ship with VS) aren't necessarily the ones you see actually being used in Windows. You have three options 1) checkboxes 2) write your own 3) buy one. Sucks, I know. Its easy to do in WPF!
-
synhershko over 14 years-1 : took me much less than 5 minutes to find a simple free one and implement it in my solution. Here are 2 samples: codeproject.com/KB/tree/MWTreeViewv2010.aspx, arstdesign.com/articles/treeviewms.html. Not perfect, but works and could be improved if you know your way around it.
-
Oliver Bock about 12 yearsYou can get around doing the drawing yourself by intercepting WM_NOTIFY and adjusting the background colour for selected nodes. I have added an answer so I can include the code.
-
Jeff Yates about 12 years@OliverBock: That's certainly the simplest way if all you need is a background color change.
-
Victor Zakharov over 10 years@synhershko: Articles are dated 2004 and 2002 respectively, I am sure there are better ways to implement same thing today.
-
Larry over 10 yearsDespite it is old (2004), the first implementation is reliable, and well coded. It fits in one class that inherits TreeView and is very simple to adapt.