![]() |
Desktop Development »
Tree Controls »
TreeView Controls
Intermediate
TreeView RearrangeBy Gabe AnguianoHow to do a TreeView rearrange. |
C#, VB, Windows, .NET 1.0, .NET 1.1VS.NET2003, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||

While merrily programming a top secret (snicker) application I was developing - I ran into a major roadblock that set me back a few days. My application was based around a treeview but I wanted to give users the ability to rearrange the node/folder structure of the treeview using drag and drop. Upon a bit of research, I found the treeview does have some sort of drag & drop support, but as far as I could tell, this just turned on the event handlers for when a user starts dragging a node. "Hmmm", I thought, "this is gonna require some custom coding."... Let's delve into my series of failures and successes leading us to a workable extension of the treeview control.
In my first attempt, I wanted all the visual goodies. I wanted the dragged node to be placed into the "slots" in between nodes as I moved over them. This, unfortunately, led me to some problems. When the node moves into a slot - the treeview structure changes and the node your mouse is currently over changes entirely, this introduced some (only slightly entertaining) node dances. I then decided to remove the node being dragged, to prevent the node dance - and it worked! My next problem was that I wanted to be able to drag the node into a "folder" node but what if the folder node is closed? I'm sure you guessed it, use Expand()! But guess what!? The dreaded node dance returned! :(
I gave up for the night and went to bed without any hope and (like many a times) woke up with an answer. Mimic the "Windows" (tm) way and implement a placeholder letting the user know where the item will be dropped. With a bit of work and a few cases of RC cola, I had the functionality I wanted.
Most of the functionality is handled within the "DragOver" event of the treeview control, however there are two other events that needed to be handled to give you the cursor effect you need.
private void treeView1_ItemDrag(object sender,
System.Windows.Forms.ItemDragEventArgs e)
{
DoDragDrop(e.Item, DragDropEffects.Move);
}
private void treeView1_DragEnter(object sender,
System.Windows.Forms.DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
Now into the DragOver event. The point to remember here is that we're dealing with two types of nodes: those that can accept children and those that can't. For nodes that can accept children, we need to have three vertical regions we have to watch for:
The non-folder nodes are divided into two vertical regions. For brevity, I will only go into the code for the "top" of the "non-folder" node. This code is divided into four main parts:
NodeMap, basically a pipe delimited set of indexes. If the new NodeMap matches the global NodeMap then method returns to minimize flickering.
#region If NodeOver is a child then cancel
TreeNode tnParadox = NodeOver;
while(tnParadox.Parent != null)
{
if(tnParadox.Parent == NodeMoving)
{
this.NodeMap = "";
return;
}
tnParadox = tnParadox.Parent;
}
#endregion
#region Store the placeholder info into a pipe delimited string
TreeNode tnPlaceholderInfo = NodeOver;
string NewNodeMap = ((int)NodeOver.Index).ToString();
while(tnPlaceholderInfo.Parent != null)
{
tnPlaceholderInfo = tnPlaceholderInfo.Parent;
NewNodeMap = tnPlaceholderInfo.Index + "|" + NewNodeMap;
}
if(NewNodeMap == this.NodeMap)
return;
else
this.NodeMap = NewNodeMap;
#endregion
#region Clear placeholders above and below
this.Refresh();
#endregion
#region Draw the placeholders
int LeftPos, RightPos;
LeftPos = NodeOver.Bounds.Left - NodeOverImageWidth;
RightPos = this.treeView1.Width - 4;
Point[] LeftTriangle = new Point[5]{
new Point(LeftPos, NodeOver.Bounds.Top - 4),
new Point(LeftPos, NodeOver.Bounds.Top + 4),
new Point(LeftPos + 4, NodeOver.Bounds.Y),
new Point(LeftPos + 4, NodeOver.Bounds.Top - 1),
new Point(LeftPos, NodeOver.Bounds.Top - 5)};
Point[] RightTriangle = new Point[5]{
new Point(RightPos, NodeOver.Bounds.Top - 4),
new Point(RightPos, NodeOver.Bounds.Top + 4),
new Point(RightPos - 4, NodeOver.Bounds.Y),
new Point(RightPos - 4, NodeOver.Bounds.Top - 1),
new Point(RightPos, NodeOver.Bounds.Top - 5)};
g.FillPolygon(System.Drawing.Brushes.Black, LeftTriangle);
g.FillPolygon(System.Drawing.Brushes.Black, RightTriangle);
g.DrawLine(new System.Drawing.Pen(Color.Black, 2),
new Point(LeftPos, NodeOver.Bounds.Top),
new Point(RightPos, NodeOver.Bounds.Top));
#endregion
The placeholders are drawn with three graphics calls to create the black line and two triangles.
The final piece to the puzzle is actually moving the dragged node. This is handled in the drag_drop event. It basically traverses the nodemap, adds the new node and removes the old one.
private void treeView1_DragDrop(object sender,
System.Windows.Forms.DragEventArgs e)
{
if(e.Data.GetDataPresent("System.Windows.Forms.TreeNode",
false) && this.NodeMap != "")
{
TreeNode MovingNode = (TreeNode)e.Data.GetData(
"System.Windows.Forms.TreeNode");
string[] NodeIndexes = this.NodeMap.Split('|');
TreeNodeCollection InsertCollection = this.treeView1.Nodes;
for(int i = 0; i < NodeIndexes.Length - 1; i++)
{
InsertCollection = InsertCollection[Int32.Parse(
NodeIndexes[i])].Nodes;
}
if(InsertCollection != null)
{
InsertCollection.Insert(Int32.Parse(NodeIndexes[
NodeIndexes.Length - 1]), (TreeNode)MovingNode.Clone());
this.treeView1.SelectedNode = InsertCollection[
Int32.Parse(NodeIndexes[NodeIndexes.Length - 1])];
MovingNode.Remove();
}
}
}
While not a completely comprehensive solution, I believe this article will be a good stepping stone for those wanting to add better drag and drop support to their applications. The code is divided clearly into regions and commented fairly well.
I look forward to your comments and suggestions. CodeProject is a great site, and I'm glad to contribute.
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 6 Jun 2005 Editor: Smitha Vijayan |
Copyright 2004 by Gabe Anguiano Everything else Copyright © CodeProject, 1999-2009 Web22 | Advertise on the Code Project |