|
Is there any option to do not mess order in which nodes were selected?
When using foreach on selNodes.Values the order is not same as order in selected tree.
|
|
|
|
|
Is there an option to select children when parent is selected? Also, if checkboxes is enabled, checking parent should check the children as well. When checkboxes is enabled, if a multiple selection is used and one checkbox's state has changed, it should change state of the other selected nodes. Thanks.
|
|
|
|
|
Can anybody help me and tell how to access checked items? What code will access each checked item and item in the loop?
Thanks
Alexander
|
|
|
|
|
I am working with your control which by the way is a great control. What I am trying to do is select multiple treenodes and drag them to another of your treeview controls on the same form. The selection is working just fine. Where the problem comes in is when trying to drag the selection. If I select multiple nodes and drag them straight across with without crossing over any of the nodes in that treeview things are fine. If I cross over any nodes in the treeview that are not selected the selection is gone and a new selection is started. Any help that you can give me on this would be appreciated.
|
|
|
|
|
Hi Larry,
I want to have Drag and Drop of the nodes across the same tree view.
Can you please let me know how drag and dropping of multiple nodes be done.
Regards
Vinutha
|
|
|
|
|
Larry,
The version posted on CodeProject is such an old code-base that I am not quite sure what could be happening.
To achieve drag & drop I have overridden all the event handlers used for drag & drop (OnItemDrag, OnDragDrop, OnDragEnter, OnDragLeave, OnDragOver, OnGiveFeedback and OnQueryContinueDrag).
Sorry I can't help you further.
There is a much newer version out that is commercial. Contact me at mik at netatonce dot net if you want to know more about this.
Regards,
Mikael
|
|
|
|
|
Is this code released under any specific license? Is it public domain, or do you intend to exercise copy rights on it?
Thanks,
-Rick
|
|
|
|
|
I don't care too much about the code posted here as long as the credit for it is not taken by someone else, as long as I am mentioned where the code is used and as long as it is not resold as a TreeView or similar component.
I do however have a much updated version of the MWTreeView that is commercial. You can contact me through email if you are interested in that (mik at netatonce fullstop net, where at is "@" and fullstop is "."). The new one is vastly improved compared to the one posted here.
|
|
|
|
|
Hi - thanks for the great control - it seems to be doing exactly what I need for my project, although I'm getting a bit of weird behaviour.
Each of my treenodes can potentially have a different imagekey set. When the tree is drawn it all displays correctly, but any nodes that are deselected seem to revert to the tree's default imagekey instead of using the node's imagekey.
[edit] it also happens with multiselect, if I click one node, then shift-select another, the first node gets the default image key[/edit]
[edit2] on closer inspection, it appears that the imagekey property of my nodes is getting cleared at some point after selection [/edit2]
Is there a property I need to set to fix this (which works fine in the regular MS tree) or do I need to add some extra code when adding my nodes to instruct the tree what to do?
Thanks,
Richard
-- modified at 4:29 Thursday 20th September, 2007
|
|
|
|
|
When you call Nodes.Clear, all nodes are correctly removed from the tree, but the selection (SelNodes) remains, which means you get an InvalidOperationException if you call FullPath on one of the Nodes in SelNodes, as it no longer has a parent.
Is this correct behaviour that SelNodes should not be affected by removal of nodes even when removing all nodes?
|
|
|
|
|
Call myMWTreeView.RemoveNode(s) if you want them removed from SelNodes as well - which I'm sure is what everyone wants.
If you have a solution as to how to find out when the Nodes property is cleared, I'm all ears
|
|
|
|
|
Hi!
Usually on a tree view when you press a key it moves the selection to the first matching node.
This default behavior is suppresed when SameLevelMultiBranch mode is selected.
How can I keep it and still use SameLevelMultiBranch mode too?
Thanks,
Laurentiu
|
|
|
|
|
This is actually true for all TreeViewMultiSelect values except Classic, not just SameLevelMultiBranch.
I have not had the intention of having this functionality in the MWTreeView.
|
|
|
|
|
Did you notice if the checkboxes are visible (with default state images) when you change nodes (eg. navigate by key down/up) the checkboxes flicker a lot?
Why do they flicker? Is there any quick fix?
|
|
|
|
|
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;
return;
case WM_PAINT:
if (internalGraphics == null)
OnResize(EventArgs.Empty);
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);
IntPtr hdc = internalGraphics.GetHdc();
Message printClientMessage = Message.Create(Handle, WM_PRINTCLIENT, hdc, IntPtr.Zero);
DefWndProc(ref printClientMessage);
OnPaint(e);
Win32.BitBlt(screenHdc, 0, 0, updateRect.right , updateRect.bottom , hdc, 0, 0, Win32.SRCCOPY);
internalGraphics.ReleaseHdc(hdc);
}
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
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
|
|
|
|
|
I just noticed that if the BackColor is Window the TreeView's background will be a mixture of backColor and black.
To fix this inconvenience I have updated the WndProc as following:
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;
return;
case WM_PAINT:
if (internalGraphics == null)
OnResize(EventArgs.Empty);
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))
{
IntPtr hdc = internalGraphics.GetHdc();
using (Graphics g = Graphics.FromHdc(hdc))
{
PaintEventArgs e = new PaintEventArgs(g, Rectangle.FromLTRB(
updateRect.left,
updateRect.top,
updateRect.right,
updateRect.bottom));
OnPaintBackground(e);
Message printClientMessage = Message.Create(Handle, WM_PRINTCLIENT, hdc, IntPtr.Zero);
DefWndProc(ref printClientMessage);
OnPaint(e);
}
Win32.BitBlt(screenHdc, 0, 0, updateRect.right, updateRect.bottom, hdc, 0, 0, Win32.SRCCOPY);
internalGraphics.ReleaseHdc(hdc);
}
Win32.EndPaint(message.HWnd, ref paintStruct);
return;
}
base.WndProc(ref message);
}
Cheers!
Laurentiu Macovei (softer)
email: alonecomp -at- gmail -dot- com
|
|
|
|
|
Thank you for all these additions.
I have had as a goal not to do anything relating in particular to the Windows operating system when developing the MWTreeView. Therefore, however nice it works, I cannot add the code you have just proposed.
If anyone wants to use these additions it is easy to add them of course.
|
|
|
|
|
Where can I purchase a comercial version of the Treeview?
|
|
|
|
|
A commercial version can be bought directly from me by contacting me at my current email address: mikATnetatonce.net where you replace 'AT' with '@'.
Contact me at this address for more information.
|
|
|
|
|
So when a node is selected/deselected the ForeColor property is changed. In my little partial implementation of your control, I'm setting the highlights to SystemColors.HighlightText and the BackColor is set to SystemColors.Highlight so that it retains the users system settings for highlights and what not. The problem occurrs when the control is disabled. Because the ForeColor/BackColor colors have been set, it no longer draws the nodes in the disabled state, but retains the ForeColor/BackColor that was set when the node was highlighted/unhighlighted. This can cause some very strage color combinations as nodes are programatically selected/deselected while the control is both enabled and disabled. If you've got an easy fix for this, please let me know.
Jebrew
|
|
|
|
|
I'm interested in your latest version. You mentioned that you were going to work on DataBinding next. Please give me information on the control and let me know what the price is.
Thanks,
Jacob
|
|
|
|
|
Hi,
before everything I would like to say, great job and thank you givin' us this great TreeView "update".
So well... ok. How to explain it.
As an example, when you have to remove node(s) and you forget to call the ClearSelNodes() method you've got really bad news. In fact, 'cause in .Net you cannot have dangling pointers, after calling the Clear() method of the TreeNodeCollection, the ArrayList (or hashing table in our case) that contain the selected nodes will contain nodes that now... got no treeview associated. This will givin' you "null reference" exception at Deselect() method in MWTreeNodeWrapper class, the next time you try to select a node.
<br />
public static void Deselect(MWTreeNodeWrapper mwtnw)<br />
{<br />
...<br />
<br />
if(mwtnw.Node.TreeView.Enabled)<br />
<br />
...<br />
The way I think we can fixe this "logical bug", is by overriding the Clear() method of the TreeNodeCollection and adding the ClearSelNodes() method call. The problem is, we cannot implemente a "new" TreeNodeCollection, I tried before and failed for some out of reach reasons caused by the Microsoft product itself.
The other way we can fixe it, is to manually check for "orphan" nodes (nodes without a TreeView) at strategicals locations in the MWTreeView control itself. "Patching" the TreeView is not a great way solving the problem and I don't wanna do this for the simple reason that if you release a new version of the TreeView, I'll be stuck to done the job each time.
Sorry for my bad english, I hope my explanations was pretty easy to understand.
So... what's your opinion about this "bug" ?
|
|
|
|
|
Thanks for the nice words.
I think I have written more code to 'help' the MS TreeView than the whole MS TreeView required...
Note that there is no bug when selecting TreeNodes when programming for it properly in current versions. Read on and I will explain why.
The code has changed quite a bit for the latest versions. This is what the static Deselect method looks like now:
public static void Deselect(MWTreeNodeWrapper mwtnw)<br />
{<br />
mwtnw.Node.ImageIndex = mwtnw.ImageIndex;<br />
mwtnw.Node.SelectedImageIndex = mwtnw.SelectedImageIndex;<br />
<br />
if( mwtnw != null &&<br />
mwtnw.Node != null &&<br />
(mwtnw.Node.TreeView == null ||<br />
mwtnw.Node.TreeView.Enabled))<br />
{<br />
mwtnw.Node.BackColor = mwtnw.BackColor;<br />
mwtnw.Node.ForeColor = mwtnw.ForeColor;<br />
}<br />
}
So no exceptions should be thrown.
It is really up to the programmer using the MWTreeView to remove TreeNodes from the SelNodes collection if they are removed from the MWTreeView.
I.e. if a ContextMenu has a 'Delete Node' item then the code behind this item should both remove the TreeNode from the SelNodes collection and from its parent (whether that is a TreeNode or the TreeView itself).
It is really a shame that you cannot instantiate TreeNodeCollections etc. Hope this changes sometime in the future.
What you write about checking for orphan TreeNodes (orphan, parent, child - what is this, some family reunion or something? ) would not be necessary if the code where TreeNodes are removed, cleared or whatever also deals with the SelNodes collection.
If we could override the TreeNodeCollections class etc the whole job of the MWTreeView would have been so much easier.
But part of the challenge is to be able to do it to the current MS TreeView
Considering all your TreeView-related questions, are you creating your own TreeView, inheriting from the MS TreeView or using the MWTreeView (curious)?
|
|
|
|
|
With all respect I've got for you and your job, I inheriting from your treeview of course !
Blindly modify your control directly in your code isn't a great programming practice and I consider peoples doin' this as robbers stealing you.
Here I'm working on an kind of personnal "Help Documentation Editor" 100% object oriented with section, sub section, each of these are makin' of "Elements" (text element, tips element, link element, table element, picture element, list element). Using WinForm with MDI Forms, I think you can see how important the treeview is. It must handle Drag&Drop, easy multiple selection and some "internals law" that telling orders like "you cannot drop a section (node) before the root section of the document (~the ultimate parent of all nodes in the treeview)".
So yeah, I'm workin' hard on the TreeView Control... and it's really pain fully !!!
I agree with you about that there's no bug, at it's real meaning, between the SelNodes and the Nodes
collections. But I think we also agree that we must "synchronize" these 2 collections and the best way doing it, is by implementing our version of the TreeNodeCollection. Seems that's impossible, I agree with you about the shame limitations of the -MS- TreeNodeCollections...
Thanks for the "uptodate version" of the Deselect() method. Are you planning to release a third version of you TreeView (soon or not) ? (I'm also curious )
|
|
|
|
|
Yep these two collections have to be synched - a shame this has to be done.
The further versions of the MWTreeView have gone commercial.
I am up to v2.1.1.4 as of yesterday actually. This version has full support for awesome very visual drag & drop (supporting multiple TreeNodes of course). There are also so many changes I just cannot list them all here.
I am also working on v3.x of the MWTreeView which has support for proper DataBinding, XML document reading etc. This is done to the extent that if a DataSource that is bound to the MWTreeView is resorted the MWTreeView immediately reflects this. DataBinding is also very customizable.
The version posted here on CodeProject is the last non-commercial version - it is still my work and nobody else should claim it as theirs yada yada yada...
|
|
|
|
|