Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

How to add a delay to DragOver event of a treeview?

Posted on 2009-04-17
10
Medium Priority
?
902 Views
Last Modified: 2012-05-06
Hello,

I have a dragover method on a treeview that checks to see what type of folder it is (based on the imageindex) and if it is the right one, that node expands.

I need to however make it so that if the user holds the item on that folder for a minimum of 1 second, then it expands. How can I do this?

Thanks!
Mel
0
Comment
Question by:melegant99
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
  • 3
10 Comments
 
LVL 15

Expert Comment

by:oobayly
ID: 24169945
Add a Timer to the form, and a TreeNode member variable
When the DragOver event fires, check the node that is under the mouse. If the node has changed, reset the timer, and store the node reference.

Then in the Timer's tick event, just expand the node
Timer timer;
TreeNode node;
 
void timer_Tick(object sender, EventArgs e) {
  // Make sure the timer is stopped and then expand the node
  timer.Stop();
  node.Expand();
}
 
void tree_DragOver(object sender, DragEventArgs e) {
  // Get the node under the mouse
  TreeView tree = sender as TreeView;
  TreeNode tempNode = tree.GetNodeAt(e.X, e.Y);
 
  // Reset the timer & store the node
  if (tempNode != null && tempNode != node) {
    if (timer.Enabled) timer.Stop();
    node = tempNode;
  }
  timer.Start();
}

Open in new window

0
 
LVL 15

Expert Comment

by:oobayly
ID: 24169969
Oops, timer.Start() should be in the if block too
TreeNode node;
 
void timer_Tick(object sender, EventArgs e) {
  // Make sure the timer is stopped and then expand the node
  timer.Stop();
  node.Expand();
}
 
void tree_DragOver(object sender, DragEventArgs e) {
  // Get the node under the mouse
  TreeView tree = sender as TreeView;
  TreeNode tempNode = tree.GetNodeAt(e.X, e.Y);
 
  // Reset the timer & store the node
  if (tempNode != null && tempNode != node) {
    if (timer.Enabled) timer.Stop();
    node = tempNode;
  }
  timer.Start();
}

Open in new window

0
 
LVL 15

Accepted Solution

by:
oobayly earned 1000 total points
ID: 24169984
Damn it, 3rd time lucky.
The Friday pub beckons.
TreeNode node;
 
void timer_Tick(object sender, EventArgs e) {
  // Make sure the timer is stopped and then expand the node
  timer.Stop();
  node.Expand();
}
 
void tree_DragOver(object sender, DragEventArgs e) {
  // Get the node under the mouse
  TreeView tree = sender as TreeView;
  TreeNode tempNode = tree.GetNodeAt(e.X, e.Y);
 
  // Reset the timer & store the node
  if (tempNode != null && tempNode != node) {
    if (timer.Enabled) timer.Stop();
    node = tempNode;
    timer.Start();
  }
}

Open in new window

0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:melegant99
ID: 24170268
The tick event does not fire until after the dragover event is complete...I need it to fire during the dragover event...Here is what I tried:


 Point pn = tvSelParts.PointToClient(new Point(e.X, e.Y));
            TreeNode tempNode = tvSelParts.GetNodeAt(pn);
            tvSelParts.Focus();
            if (tempNode.Tag != null && tempNode.Tag.ToString().Length >= 4 && tempNode.Tag.ToString().Substring(0, 4) == "fldr" && tempNode.ImageIndex != 9)
                {
                    timeNode.Stop();
                    tn = tempNode;
                    timeNode.Start();
                }
                if (tn.ImageIndex == 9)
                    e.Effect = DragDropEffects.Copy;
                else
                    e.Effect = DragDropEffects.None;
                if (tn.Parent != null && (tn.Parent.Name != "eq" || tn.Name != "add"))
                    tvSelParts.SelectedNode = tn;
            }
 
//TICK EVENT
        private void timeNode_Tick(object sender, EventArgs e)
        {
            timeNode.Stop();
            if(tn != null)
            tn.Expand();
            
        }

Open in new window

0
 
LVL 39

Expert Comment

by:abel
ID: 24170318
Though I see that there have been some answers / comments already, I was meanwhile working up a solution and apparently alongside a different path. This works for me, and all it takes is a simple variable extra in the DragOver event. I posted the whole code so you can cut and paste it in a new form to see how it works.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
 
namespace TestCSharpWindowsForms.EE_forms
{
    public partial class Q24332302 : Form
    {
        public Q24332302()
        {
            InitializeComponent();
        }
 
        private void Q24332302_Load(object sender, EventArgs e)
        {
            TreeNode root = treeView1.Nodes.Add("root item");
            TreeNode child = root.Nodes.Add("c:\\");
            child.Nodes.Add("File1.txt");
            child.Nodes.Add("File2.txt");
            child = root.Nodes.Add("d:\\");
            child.Nodes.Add("OtherFile1.txt");
            child.Nodes.Add("OtherFile2.txt");
            root.Expand();
 
            root = treeView2.Nodes.Add("other root item");
            child = root.Nodes.Add("MAIN");
            child.Nodes.Add("Interesting Contents 1");
            child.Nodes.Add("Interesting Contents 2");
            child = root.Nodes.Add("DATA");
            child.Nodes.Add("Data Contents 1");
            child.Nodes.Add("Data Contents 2");
            root.Expand();
        }
 
        private void Q24332302_FormClosed(object sender, FormClosedEventArgs e)
        {
            Application.Exit();
        }
 
        private void treeView_ItemDrag(object sender, ItemDragEventArgs e)
        {
            DoDragDrop(e.Item, DragDropEffects.Move);
 
            if (!isValidDrag(sender, e))
                return;
 
        }
 
        private void treeView_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Move;
        }
 
        private void treeView_DragDrop(object sender, DragEventArgs e)
        {
            if (!isValidDrag(sender, e))
                return;
 
            TreeView senderTV = sender as TreeView;
            TreeNode destinationNode = getDraggedTargetNode(senderTV, e);
            TreeNode sourceNode = getDraggedSourceNode(e);
 
            if (destinationNode.TreeView != sourceNode.TreeView)
            {
                destinationNode.Nodes.Add( (TreeNode) sourceNode.Clone());
                destinationNode.Expand();
 
                //Remove source node
                sourceNode.Remove();
            }
        }
 
        private TreeNode getDraggedTargetNode(TreeView tv, DragEventArgs e)
        {
            Point pt = tv.PointToClient(new Point(e.X, e.Y));
            return tv.GetNodeAt(pt);
        }
 
        private TreeNode getDraggedTargetNode(TreeView tv, MouseEventArgs e)
        {
            Point pt = new Point(e.X, e.Y);
            return tv.GetNodeAt(pt);
        }
 
        private TreeNode getDraggedSourceNode(DragEventArgs e)
        {
            return e.Data.GetData(typeof(TreeNode)) as TreeNode;
        }
 
        private bool isValidDrag(object sender, DragEventArgs e)
        {
            if (!e.Data.GetDataPresent(typeof(TreeNode)))
                return false;
 
            if (sender == null || sender as TreeView == null)
                return false;     // not a treeview
 
            return true;
        }
 
        private bool isValidDrag(object sender, ItemDragEventArgs e)
        {
            if (e.Item as TreeNode == null)
                return false;
 
            if (sender == null || sender as TreeView == null)
                return false;     // not a treeview
 
            return true;
        }
 
 
        private TreeNode m_previousTargetNode = null;
        private DateTime m_enteringNodeTime = DateTime.MaxValue;
        private void treeView_DragOver(object sender, DragEventArgs e)
        {
            if (!isValidDrag(sender, e))
                return;
 
            TreeNode targetNode = getDraggedTargetNode(sender as TreeView, e);
 
            if (m_previousTargetNode != null && m_previousTargetNode != targetNode)
                m_previousTargetNode.BackColor = Color.White;
 
            if (targetNode != null)
            {
                if (targetNode.BackColor != Color.SteelBlue)
                    m_enteringNodeTime = DateTime.Now;
 
                targetNode.BackColor = Color.SteelBlue;                
                m_previousTargetNode = targetNode;
 
                if(m_enteringNodeTime < DateTime.Now.AddSeconds(-1.0))
                    targetNode.Expand();
            }
 
        }
 
    }
}
 
 
////////////////////////////////////////////////////////////////////////////////////
// And if you do not want to build the form yourself, paste this in the Designer.cs //
////////////////////////////////////////////////////////////////////////////////////
namespace TestCSharpWindowsForms.EE_forms
{
    partial class Q24332302
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
 
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
 
        #region Windows Form Designer generated code
 
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.treeView1 = new System.Windows.Forms.TreeView();
            this.treeView2 = new System.Windows.Forms.TreeView();
            this.SuspendLayout();
            // 
            // treeView1
            // 
            this.treeView1.AllowDrop = true;
            this.treeView1.Location = new System.Drawing.Point(12, 12);
            this.treeView1.Name = "treeView1";
            this.treeView1.Size = new System.Drawing.Size(205, 212);
            this.treeView1.TabIndex = 0;
            this.treeView1.DragDrop += new System.Windows.Forms.DragEventHandler(this.treeView_DragDrop);
            this.treeView1.DragEnter += new System.Windows.Forms.DragEventHandler(this.treeView_DragEnter);
            this.treeView1.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(this.treeView_ItemDrag);
            this.treeView1.DragOver += new System.Windows.Forms.DragEventHandler(this.treeView_DragOver);
            // 
            // treeView2
            // 
            this.treeView2.AllowDrop = true;
            this.treeView2.Location = new System.Drawing.Point(268, 13);
            this.treeView2.Name = "treeView2";
            this.treeView2.Size = new System.Drawing.Size(193, 211);
            this.treeView2.TabIndex = 1;
            this.treeView2.DragDrop += new System.Windows.Forms.DragEventHandler(this.treeView_DragDrop);
            this.treeView2.DragEnter += new System.Windows.Forms.DragEventHandler(this.treeView_DragEnter);
            this.treeView2.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(this.treeView_ItemDrag);
            // 
            // Q24332302
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(499, 264);
            this.Controls.Add(this.treeView2);
            this.Controls.Add(this.treeView1);
            this.Name = "Q24332302";
            this.Text = "Q24332302";
            this.Load += new System.EventHandler(this.Q24332302_Load);
            this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.Q24332302_FormClosed);
            this.ResumeLayout(false);
 
        }
 
        #endregion
 
        private System.Windows.Forms.TreeView treeView1;
        private System.Windows.Forms.TreeView treeView2;
    }
}

Open in new window

0
 
LVL 39

Expert Comment

by:abel
ID: 24170343
To dig up the important part, let's paste the DragOver event here for convenience. Note the part where m_enteringNodeTime is set and where it is compared. I set the time to one second, but you can use any time you like. No complexities with timers etc.

private TreeNode m_previousTargetNode = null;
private DateTime m_enteringNodeTime = DateTime.MaxValue;
private void treeView_DragOver(object sender, DragEventArgs e)
{
    if (!isValidDrag(sender, e))
        return;
 
    TreeNode targetNode = getDraggedTargetNode(sender as TreeView, e);
 
    if (m_previousTargetNode != null && m_previousTargetNode != targetNode)
        m_previousTargetNode.BackColor = Color.White;
 
    if (targetNode != null)
    {
        if (targetNode.BackColor != Color.SteelBlue)
            m_enteringNodeTime = DateTime.Now;
 
        targetNode.BackColor = Color.SteelBlue;                
        m_previousTargetNode = targetNode;
 
        if(m_enteringNodeTime < DateTime.Now.AddSeconds(-1.0))
            targetNode.Expand();
    }
 
}

Open in new window

0
 
LVL 39

Assisted Solution

by:abel
abel earned 1000 total points
ID: 24170384
In your own code, you inevitably have a piece where you determine what node is there (in my code getDraggedTargetNode). This automatically changes at some point when the mouse moves over to another node. I use that moment where it changes to color the background of the targeted node.

This color I then use as a trigger to know whether I should set the "timer". It is not a timer, it is more a memory of the moment in time that the mouse enters the node that we want to delay for expanding.

Then, and that's the last two lines in the code above, I check whether that moment was about 1 second in the past. If it was, I expand. If not, I do nothing. The effect is that expansion only happens if the mouse stays on top of an item for as long as one second.

Note that I did not include movement. When you check the windows start menu, the movement of the mouse must be to a certain minimum. For this code, continuous movement is not a problem.

-- Abel --
0
 

Author Closing Comment

by:melegant99
ID: 31571543
Both nice solutions, thanks!
0
 
LVL 39

Expert Comment

by:abel
ID: 24170545
> Both nice solutions, thanks!

you're welcome. I got it from that you have it working now? :)
0
 

Author Comment

by:melegant99
ID: 24170575
Yes, works great!
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
Entity Framework is a powerful tool to help you interact with the DataBase but still doesn't help much when we have a Stored Procedure that returns more than one resultset. The solution takes some of out-of-the-box thinking; read on!
Visualize your data even better in Access queries. Given a date and a value, this lesson shows how to compare that value with the previous value, calculate the difference, and display a circle if the value is the same, an up triangle if it increased…
In this video, Percona Solution Engineer Rick Golba discuss how (and why) you implement high availability in a database environment. To discuss how Percona Consulting can help with your design and architecture needs for your database and infrastr…

618 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question