Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/vim/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在使用拖放时,我是否可以使树状视图扩展用户悬停的节点? 简言之:_C#_Winforms_Treeview_Hover_Drag And Drop - Fatal编程技术网

C# 在使用拖放时,我是否可以使树状视图扩展用户悬停的节点? 简言之:

C# 在使用拖放时,我是否可以使树状视图扩展用户悬停的节点? 简言之:,c#,winforms,treeview,hover,drag-and-drop,C#,Winforms,Treeview,Hover,Drag And Drop,在进行拖放操作时,悬停在.Net 2.0中是否有任何内置函数可以扩展TreeNodes 我在VisualStudio2005中使用C# 更详细地说: 我已经用一个多级多节点树(想想组织结构图或文件/文件夹对话框)填充了一个Treeview控件,我想使用拖放来移动树中的节点 拖放代码运行良好,我可以拖放到任何可见节点上,但是我希望我的控件在文件夹窗格上拖动文件时的行为与Windows资源管理器相同。具体地说,如果将鼠标悬停1/2秒左右,我希望每个文件夹都能打开 我已经开始使用线程和睡眠方法开发一个

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

我在VisualStudio2005中使用C#

更详细地说: 我已经用一个多级多节点树(想想组织结构图或文件/文件夹对话框)填充了一个
Treeview
控件,我想使用拖放来移动树中的节点

拖放代码运行良好,我可以拖放到任何可见节点上,但是我希望我的控件在文件夹窗格上拖动文件时的行为与Windows资源管理器相同。具体地说,如果将鼠标悬停1/2秒左右,我希望每个文件夹都能打开

我已经开始使用
线程
睡眠
方法开发一个解决方案,但我遇到了一些问题,想知道是否已经有了解决方案,如果没有,我将全力以赴学习如何使用线程(是时候了,但我希望这个应用程序能尽快推出)

我是否需要编写自己的代码来处理在拖放模式下悬停时展开
TreeNode

编辑

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

DelayedAction

public class DelayedAction<T>
{
    private SynchronizationContext _syncContext;
    private Action<T> _action;
    private int _delay;

    private Thread _thread;

    public DelayedAction(Action<T> action)
        : this(action, 0)
    {
    }

    public DelayedAction(Action<T> 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);
    }
}
public class AutoExpandTreeView : TreeView
{
    DelayedAction<TreeNode> _expandNode;

    public AutoExpandTreeView()
    {
        _expandNode = new DelayedAction<TreeNode>((node) => node.Expand(), 500);
    }

    private TreeNode _prevNode;
    protected override void OnDragOver(DragEventArgs e)
    {
        Point clientPos = PointToClient(new Point(e.X, e.Y)); 
        TreeViewHitTestInfo hti = HitTest(clientPos);
        if (hti.Node != null && hti.Node != _prevNode)
        {
            _prevNode = hti.Node;
            _expandNode.RunAfterDelay(hti.Node);
        }
        base.OnDragOver(e);
    }
}

您可以使用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(e.X, e.Y);
        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();
            }
        }
    }
}

不起作用。。。我试过这个。在拖放模式下,不会触发OnNodeMouseHover。+1表示使用Dragver的解决方案。很好的“我还在同一个节点上吗?”逻辑也很好。很好,非常感谢。我没有意识到你可以在bady方法之外像那样实例化,所以我学到了更多:-)还有一个问题,你提到的IconObject是什么?我从您的代码中导出了一个解决方案,但没有使用它。另外,我忽略了listview代码,因为它与我的情况无关。IconObject ListView是否相关?这来自一个允许管理和关联不同对象的项目;它包含业务、人员、计算机、软件等。业务包含部门,部门包含人员、计算机、计算机包含软件等。某些对象分配给其他对象(显示在树视图中),而其他对象未分配并保留在常规池(如未分配的计算机池)中,显示在列表视图中。所有对象都继承自IconObject,它是我定义公共属性和逻辑的基类。(子类定义了一个列表/树图像、一些额外的属性和其他一些)