树形视图拖放效果无法工作。

10
我似乎遇到了一些问题。我有一个表单,其中有一个树形视图。在这个树形视图中,有“文件夹”和“项目”。我允许用户移动节点/更改文件夹和项目的层次结构。
我试图在拖放操作进行时更改鼠标光标,但似乎不起作用。我已经更改了所有必要的值,并在不同事件期间更改了鼠标光标,但没有效果。
下面的代码是否缺少某些内容,导致无法正确执行?基本上,显示的光标始终是默认的拖放光标(移动、复制等)...请注意,我还启用了树形视图的HotTracking以启用GiveFeedback,并且它会触发断点。
[编辑] - 感谢Hans提供的解决方案。基本上,DoDragDrop调用必须针对您要使用的控件进行定位,方法是使用其FQN。无论您的源控件是否触发ItemDrag事件,您都必须明确指定它。请参见下面更新的代码。
        #region Drag and Drop Methods and Event Handlers
        /// <summary>
        /// Performs the necessary actions when the user drags and drops a node around the treeview.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tv_Terms_DragDrop(object sender, DragEventArgs e)
        {
            // Retrieve the client coordinates of the drop location.
            Point targetPoint = this.tv_Terms.PointToClient(new Point(e.X, e.Y));

            // Retrieve the node at the drop location.
            TreeNode targetNode = this.tv_Terms.GetNodeAt(targetPoint);

            // confirm that the target node isn't null
            // (for example if you drag outside the control)
            if (targetNode != null)
            {

                // Retrieve the node that was dragged.
                TreeNode draggedNode = (TreeNode)e.Data.GetData(typeof(TreeNode));
                TreeNode draggedParentNode = draggedNode.Parent;

                //PERFORM DB OPERATIONS HERE>>

                // Expand the node at the location 
                // to show the dropped node.
                targetNode.Expand();
            }
        }

        /// <summary>
        /// Adds the necessary effect when dragging.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tv_Terms_ItemDrag(object sender, ItemDragEventArgs e)
        {
            this.tv_Terms.DoDragDrop(e.Item, DragDropEffects.Move);
        }

        /// <summary>
        /// Adds the necessary effect when dragging.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tv_Terms_DragEnter(object sender, DragEventArgs e)
        {
            if(e.Data.GetDataPresent(typeof(TreeNode)) == true)
                e.Effect = DragDropEffects.Move;
        }

        /// <summary>
        /// Selects the appropriate node when the user is dragging an item.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tv_Terms_DragOver(object sender, DragEventArgs e)
        {
            //THIS METHOD AUTO-SCROLLS THE TREEVIEW IF YOU REACH THE EDGES...
            this.tv_Terms.Scroll();
            TreeNode node = this.tv_Terms.GetNodeAt(this.tv_Terms.PointToClient(new Point(e.X, e.Y)));
            if (node != null)
            {
                NodeInfo info = node.Tag as NodeInfo;

                if (!info.IsContainer)
                    node = node.Parent;

                this.tv_Terms.SelectedNode = node;
            }
        }

        private void tv_Terms_GiveFeedback(object sender, GiveFeedbackEventArgs e)
        {
            //I DON'T CARE WHAT TYPE OF DRAG IT IS, ALWAYS USE THE CUSTOM CURSOR.
            e.UseDefaultCursors = false;
            Cursor.Current = lastcursor;                
        }

        //I SET/CACHE THE MOUSE CURSOR HERE
        private void tv_Terms_MouseDown(object sender, MouseEventArgs e)
        {
            TreeNode node = this.tv_Terms.GetNodeAt(e.X, e.Y);
            if (node != null)
            {
                //THIS METHOD CREATES THE CUSTOM CURSOR.
                Bitmap curs = Helpers.CreateNodeCursorIcon(this.imageList1.Images[node.ImageIndex], node.Text);
                this.lastcursor = new Cursor(curs.GetHicon());
                //I CONFIRM THE PROPER CURSOR BY PLACING THE IMAGE IN A P.B.
                this.pictureBox1.Image = curs;
                Cursor.Current = lastcursor;
            }

        }

        #endregion
1个回答

9
    DoDragDrop(e.Item, DragDropEffects.Move);

你的tv_Terms_ItemDrag()方法中存在一个微妙的错误,它使用了表单的DoDragDrop()方法。在你的情况下很重要,因为GiveFeedback事件是在拖动源上触发的,而不是在放置目标上触发。换句话说,你的GiveFeedback事件永远不会触发。通过调试器非常容易看到,只需在事件处理程序上设置断点即可看到它从未运行过。修复方法:

    private void tv_Terms_ItemDrag(object sender, ItemDragEventArgs e)
    {
        tv_Terms.DoDragDrop(e.Item, DragDropEffects.Move);
    }

最好使用此方法创建光标。在 DragEnter 事件处理程序中应更加谨慎,以便它不允许放置 所有东西,使用 e.Data.GetDataPresent(typeof(TreeNode)) 进行验证。并且在 DragOver 中删除光标操作。


奇怪的是,GiveFeedback确实会触发...但我会尝试在ItemDrag中指定TreeView,看看是否可以解决这个问题。 - MaxOvrdrv
哦...我的...天啊!非常感谢!我还在DragEnter中添加了检查(很有意义!)...请查看更新的问题帖子。非常感谢! :) - MaxOvrdrv
还有一件事:我应该在哪里将光标恢复到正常? - MaxOvrdrv
"在DragOver中移除光标操纵。你一直在努力尝试使其工作,发现它没有效果,然后忘记删除它。这个this.Cursor赋值会阻止光标返回正常状态。" - Hans Passant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接