使用拖放时,我可以使Treeview扩展用户hover的节点吗?

简单来说:

在拖放操作正在进行的同时,.Net 2.0中是否有任何内置函数可以扩展TreeNode

我在Visual Studio 2005中使用C#。

更详细:

我已经使用多级多线树(想想组织图或文件/文件夹对话框)填充了Treeview控件,我想使用拖放来移动树中的节点。

拖放代码运行良好,我可以放到任何可见的节点上,但是我希望我的控件在Windows资源管理器窗格上拖动文件时的行为就像Windows资源管理器一样。 具体来说,我希望每个文件夹打开,如果徘徊1/2秒左右。

我已经开始使用ThreadingSleep方法开发一个解决方案,但是我遇到了问题,并且想知道是否已经存在某些问题,如果不是,我会指责并学习如何使用线程(这是关于时间的,但我是希望快速推出这个应用程序)

在拖放模式中盘旋时,是否需要编写自己的代码来处理扩展TreeNode

您可以使用DragOver事件; 拖动对象时会反复触发打开延迟后可以通过两个额外的变量很容易地完成,这些变量会记录鼠标下的最后一个对象和时间。 不需要线程或其他技巧(在我的示例中为lastDragDestination和lastDragDestinationTime)

从我自己的代码:

 TreeNode lastDragDestination = null; DateTime lastDragDestinationTime; private void tvManager_DragOver(object sender, DragEventArgs e) { IconObject dragDropObject = null; TreeNode dragDropNode = null; //always disallow by default e.Effect = DragDropEffects.None; //make sure we have data to transfer if (e.Data.GetDataPresent(typeof(TreeNode))) { dragDropNode = (TreeNode)e.Data.GetData(typeof(TreeNode)); dragDropObject = (IconObject)dragDropNode.Tag; } else if (e.Data.GetDataPresent(typeof(ListViewItem))) { ListViewItem temp (ListViewItem)e.Data.GetData(typeof(ListViewItem)); dragDropObject = (IconObject)temp.Tag; } if (dragDropObject != null) { TreeNode destinationNode = null; //get current location Point pt = new Point(eX, eY); pt = tvManager.PointToClient(pt); destinationNode = tvManager.GetNodeAt(pt); if (destinationNode == null) { return; } //if we are on a new object, reset our timer //otherwise check to see if enough time has passed and expand the destination node if (destinationNode != lastDragDestination) { lastDragDestination = destinationNode; lastDragDestinationTime = DateTime.Now; } else { TimeSpan hoverTime = DateTime.Now.Subtract(lastDragDestinationTime); if (hoverTime.TotalSeconds > 2) { destinationNode.Expand(); } } } } 

编辑

我有一个新的解决方案,有点牵强,但它的工作原理…它使用DelayedAction类来处理主线程上的操作的延迟执行:

DelayedAction

 public class DelayedAction { private SynchronizationContext _syncContext; private Action _action; private int _delay; private Thread _thread; public DelayedAction(Action action) : this(action, 0) { } public DelayedAction(Action action, int delay) { _action = action; _delay = delay; _syncContext = SynchronizationContext.Current; } public void RunAfterDelay() { RunAfterDelay(_delay, default(T)); } public void RunAfterDelay(T param) { RunAfterDelay(_delay, param); } public void RunAfterDelay(int delay) { RunAfterDelay(delay, default(T)); } public void RunAfterDelay(int delay, T param) { Cancel(); InitThread(delay, param); _thread.Start(); } public void Cancel() { if (_thread != null && _thread.IsAlive) { _thread.Abort(); } _thread = null; } private void InitThread(int delay, T param) { ThreadStart ts = () => { Thread.Sleep(delay); _syncContext.Send( (state) => { _action((T)state); }, param); }; _thread = new Thread(ts); } } 

AutoExpandTreeView

 public class AutoExpandTreeView : TreeView { DelayedAction _expandNode; public AutoExpandTreeView() { _expandNode = new DelayedAction((node) => node.Expand(), 500); } private TreeNode _prevNode; protected override void OnDragOver(DragEventArgs e) { Point clientPos = PointToClient(new Point(eX, eY)); TreeViewHitTestInfo hti = HitTest(clientPos); if (hti.Node != null && hti.Node != _prevNode) { _prevNode = hti.Node; _expandNode.RunAfterDelay(hti.Node); } base.OnDragOver(e); } }