Reputation: 2644
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?
Upvotes: 26
Views: 72081
Reputation: 5105
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;
Upvotes: 5
Reputation: 73
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
Upvotes: 5
Reputation:
You might look at a 3rd party solution. The Infragistics tree does this. Not free, but the time spent trying to find a solution isn't really free, either.
Upvotes: 4
Reputation: 62377
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.
Upvotes: 10
Reputation: 2256
Are check-boxes an option? or do you want the select like you get in a list box?
There is a multi-select tree control available on CodeProject:Multi-Select Tree View
Upvotes: 6