Click here to Skip to main content
15,867,141 members
Articles / Programming Languages / XML

Multi-select Treeview control v2.0

Rate me:
Please Sign up or sign in to vote.
4.64/5 (16 votes)
15 Aug 2004CPOL 229.8K   6.2K   48   52
Multi-select Treeview control v2.0

Screenshots

Image 1

Image 2

Image 3

Image 4

Image 5

Image 6

Image 7

Image 8

Image 9

Introduction

This is a multi select TreeView Control for the .NET Framework. It is possible to select TreeNodes in multiple ways with or without constraints.

Details

The MWTreeView has a few ways of mouse-selecting the TreeNodes by painting anything from a rubberband to very graphical representations. There is even the possibility, using GDI+, to customize the mouse-selection. It is also possible to have TreeNodes of various colors within the same MWTreeView with multi-selection still working. The MWTreeView has a massive amount of configurable settings so that anyone should be able to tailor it to their needs.

Note that when selecting TreeNodes in code, the SelectNode (DeselectNode also exists) method should be used. Note that when changing the colors of a TreeNode, the ChangeColors method should be used. Do not just change the colors of a TreeNode.

Note that in order to iterate through the selected TreeNodes, the following method has to be used (selected TreeNodes are stored in a Hashtable):

C#
foreach(MWTreeNodeWrapper mwtnw in mwtvMWTreeView.SelNodes.Values)
{
   MessageBox.Show("The " + mwtnw.Node.Text + 
    " TreeNode is selected.");
}

Contacting Me

I can be reached through the forum here at CodeProject.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Sweden Sweden
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionSorting selected nodes Pin
Abrakadabraaaaa25-Jul-22 23:00
Abrakadabraaaaa25-Jul-22 23:00 
QuestionOption to select children when parent is selected Pin
revitarkitek12-Feb-20 7:28
revitarkitek12-Feb-20 7:28 
QuestionHow to access checked items? Pin
Alexander Pikus3-Nov-08 19:09
Alexander Pikus3-Nov-08 19:09 
GeneralDraga and Drop Behavior Pin
Dewayne Dodd5-Mar-08 10:45
Dewayne Dodd5-Mar-08 10:45 
GeneralRe: Draga and Drop Behavior Pin
vinutha kempanna5-Mar-08 10:57
vinutha kempanna5-Mar-08 10:57 
GeneralRe: Draga and Drop Behavior Pin
Mikael Wiberg5-Mar-08 19:03
Mikael Wiberg5-Mar-08 19:03 
QuestionGreat code, license question? Pin
thatrickguy29-Nov-07 5:53
thatrickguy29-Nov-07 5:53 
AnswerRe: Great code, license question? Pin
Mikael Wiberg29-Nov-07 6:42
Mikael Wiberg29-Nov-07 6:42 
GeneralOdd behaviour on deselect [modified] Pin
benjymous19-Sep-07 22:09
benjymous19-Sep-07 22:09 
GeneralNodes.Clear Doesn't Clear SelNodes Pin
Christopher Theunissen20-Apr-07 1:16
Christopher Theunissen20-Apr-07 1:16 
GeneralRe: Nodes.Clear Doesn't Clear SelNodes Pin
Mikael Wiberg20-Apr-07 6:07
Mikael Wiberg20-Apr-07 6:07 
QuestionSearch as you type doesn't work on the SameLevelMultiBranch Pin
DotNetWise2-Apr-07 0:58
DotNetWise2-Apr-07 0:58 
AnswerRe: Search as you type doesn't work on the SameLevelMultiBranch [modified] Pin
Mikael Wiberg9-Apr-07 0:27
Mikael Wiberg9-Apr-07 0:27 
QuestionCheckboxes Pin
DotNetWise22-Dec-06 12:59
DotNetWise22-Dec-06 12:59 
AnswerRe: Checkboxes Pin
DotNetWise22-Dec-06 14:17
DotNetWise22-Dec-06 14:17 
I have researched a little bit and get it very smoothly and cool!

Add this code to it and allow the DoulbeBufferStyle to rock!
(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint) //for .net 2.0 (for 1.1 remove the Optimized word)

Here are the changes:
#1 So, first of all: uncomment the UserPaint from the ctor:

this.SetStyle(System.Windows.Forms.ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(System.Windows.Forms.ControlStyles.DoubleBuffer, true);
this.SetStyle(System.Windows.Forms.ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(System.Windows.Forms.ControlStyles.ResizeRedraw, true);
this.SetStyle(System.Windows.Forms.ControlStyles.Selectable, true);
this.SetStyle(System.Windows.Forms.ControlStyles.SupportsTransparentBackColor, true);
this.SetStyle(System.Windows.Forms.ControlStyles.UserPaint, true);



#2 Then declare two private variables
private Bitmap internalBitmap = null;
private Graphics internalGraphics = null;


#3 The most important thing: Change the behavior of WndProc
protected override void WndProc(ref Message message)
{
	const int WM_ERASEBKGND = 0x0014;
	const int WM_PAINT = 0x000F;
	const int WM_PRINTCLIENT = 0x0318;
	switch (message.Msg)
	{
		case WM_ERASEBKGND:
		    message.Msg = (int)0x0000; //reset 
		    return;
		case WM_PAINT:
			// The designer host does not call OnResize()                    
			if (internalGraphics == null)
				OnResize(EventArgs.Empty);

			//Set up 
			Win32.RECT updateRect = new Win32.RECT();
			if (Win32.GetUpdateRect(message.HWnd, ref updateRect, false) == 0)
				break;

			Win32.PAINTSTRUCT paintStruct = new Win32.PAINTSTRUCT();

			IntPtr screenHdc = Win32.BeginPaint(message.HWnd, ref paintStruct);
			using (Graphics screenGraphics = Graphics.FromHdc(screenHdc))
			{

				PaintEventArgs e = new PaintEventArgs(internalGraphics, Rectangle.FromLTRB(
					updateRect.left,
					updateRect.top,
					updateRect.right,
					updateRect.bottom));
				OnPaintBackground(e);


				//Draw Internal Graphics
				IntPtr hdc = internalGraphics.GetHdc();
				Message printClientMessage = Message.Create(Handle, WM_PRINTCLIENT, hdc, IntPtr.Zero);
				DefWndProc(ref printClientMessage);

				//Add the missing OnPaint() call
				OnPaint(e);


				//Draw Screen Graphics

				//.NET way: extremly flickering way
				//screenGraphics.DrawImage(internalBitmap, 0, 0); 

				//coolest way: No flickering at all!!!
				Win32.BitBlt(screenHdc, 0, 0, updateRect.right , updateRect.bottom , hdc, 0, 0, Win32.SRCCOPY);
				internalGraphics.ReleaseHdc(hdc);
				
			}

			//Tear down
			Win32.EndPaint(message.HWnd, ref paintStruct);

			return;
	}
	base.WndProc(ref message);
}


#4 Add cleaning up methods and change resizing behavior:
private void DisposeInternal()
{
	if (internalGraphics != null)
		internalGraphics.Dispose();
	if (internalBitmap != null)
		internalBitmap.Dispose();

}

protected override void OnResize(EventArgs e)
{
	if (internalBitmap == null 
		|| internalBitmap.Width != Width
		|| internalBitmap.Height != Height)
	{

		if (Width != 0 && Height != 0)
		{
			DisposeInternal();
			internalBitmap = new Bitmap(Width, Height);
			internalGraphics = Graphics.FromImage(internalBitmap);
		}
	}
}


#5 Call the cleaning on dispose: Change the Dispose method as below:
protected override void Dispose(bool disposing)
{
	if (disposing)
	{
		DisposeInternal();
		if (components != null)
		{
			components.Dispose();
		}
	}

	base.Dispose(disposing);
}


#6 The final step: Add the Win32 P/Invoke helper class
/// <summary>
/// Win32 PInvoke declarations
/// </summary>
internal class Win32
{
	[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
	public static extern int BitBlt(IntPtr hDC, int x, int y, int nWidth, int nHeight, IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);
	public const int SRCCOPY = 0xcc0020;

	[DllImport("User32.dll")]
	public static extern int GetUpdateRect(IntPtr hwnd, ref RECT rect, bool erase);

	[DllImport("User32.dll", SetLastError = true)]
	public static extern bool GetWindowRect(IntPtr handle, ref RECT rect);

	[DllImport("User32.dll")]
	public static extern IntPtr BeginPaint(IntPtr hWnd, ref PAINTSTRUCT paintStruct);

	[DllImport("User32.dll")]
	public static extern bool EndPaint(IntPtr hWnd, ref PAINTSTRUCT paintStruct);

	[StructLayout(LayoutKind.Sequential)]
	public struct RECT
	{
		public int left;
		public int top;
		public int right;
		public int bottom;
	}

	[StructLayout(LayoutKind.Sequential)]
	public struct PAINTSTRUCT
	{
		public IntPtr hdc;
		public int fErase;
		public RECT rcPaint;
		public int fRestore;
		public int fIncUpdate;
		public int Reserved1;
		public int Reserved2;
		public int Reserved3;
		public int Reserved4;
		public int Reserved5;
		public int Reserved6;
		public int Reserved7;
		public int Reserved8;
	}
}


#7 That's all!
Now it works just great! Thanks to GOD that M$ invented BitBlt, as the coolest function of the whole Windows API.

Hope this helps!

P.S. To the author: Please include the changes in the downloadable sources. Thanks!



Laurentiu Macovei (softer)
email: alonecomp -at- gmail -dot- com
GeneralRe: Checkboxes Pin
DotNetWise22-Dec-06 14:53
DotNetWise22-Dec-06 14:53 
GeneralRe: Checkboxes Pin
Mikael Wiberg22-Dec-06 17:46
Mikael Wiberg22-Dec-06 17:46 
GeneralComercial Version Pin
FooDogCom16-Dec-06 13:44
FooDogCom16-Dec-06 13:44 
GeneralRe: Comercial Version Pin
Mikael Wiberg16-Dec-06 20:06
Mikael Wiberg16-Dec-06 20:06 
GeneralProblem with the highlighting/unhighlighting Pin
jebrew20-Sep-06 6:08
jebrew20-Sep-06 6:08 
GeneralLatest Version with DataBinding Pin
Jacob Shepherd29-Nov-05 12:46
Jacob Shepherd29-Nov-05 12:46 
GeneralDeep Logic bug about selecting node(s) Pin
Le_MuLoT13-Sep-05 4:17
Le_MuLoT13-Sep-05 4:17 
AnswerRe: Deep Logic bug about selecting node(s) Pin
Mikael Wiberg14-Sep-05 2:04
Mikael Wiberg14-Sep-05 2:04 
GeneralRe: Deep Logic bug about selecting node(s) Pin
Le_MuLoT14-Sep-05 3:13
Le_MuLoT14-Sep-05 3:13 
GeneralRe: Deep Logic bug about selecting node(s) Pin
Mikael Wiberg14-Sep-05 3:51
Mikael Wiberg14-Sep-05 3:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.