C# - Winforms - 触摸拖动时不显示自定义拖动图像

时间:2015-10-28 00:10:05

标签: c# winforms drag-and-drop touchscreen

我有一个用C#编写的旧版WinForms应用程序,具有自定义拖放功能。此应用程序在触摸屏设备上运行时会出现问题,例如Surface Pro 3.

基本上有一个树形视图控件允许将项目拖动到应用程序的不同区域并进行一些计算。如果我使用鼠标或手写笔,则会在屏幕上绘制自定义拖动图像。如果我使用触摸拖动项目,则不会显示图像,但代码会正确执行,包括绘制自定义光标。

似乎没有显示自定义拖动图像,因为鼠标光标被O.S隐藏了。在触摸拖动操作期间。如何显示拖动图像?

更新 这是一些代码来演示我想要解决的问题。创建一个新的WinForms应用程序,向其添加树视图并连接事件。您会注意到,如果您使用手写笔或鼠标,拖动操作将显示一个图标。如果您触摸拖动某个项目,则不显示任何内容。

public Form1()
    {
        InitializeComponent();

        TreeNode node = new TreeNode("welp");

        treeView1.Nodes.Add(node);
        treeView1.Nodes.Add(node);
        treeView1.Nodes.Add(node);
        treeView1.Nodes.Add(node);
        treeView1.Nodes.Add(node);
        treeView1.Nodes.Add(node);
        treeView1.Nodes.Add(node);
        treeView1.Nodes.Add(node);
        treeView1.Nodes.Add(node);
        treeView1.Nodes.Add(node);
    }

    private void treeView1_DragEnter(object sender, DragEventArgs e)
    {
        e.Effect = DragDropEffects.Move;
    }

    private void treeView1_GiveFeedback(object sender, GiveFeedbackEventArgs e)
    {
        e.UseDefaultCursors = true;
    }

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

2 个答案:

答案 0 :(得分:0)

好的,所以我按照我想要的方式完成了这项工作。这并不容易,它可能不是首选的方式,但它做了我想要的,而且我正处于紧张状态,以完成它。

首先,我发现了这篇文章Shell Style Drag and Drop。它在大多数情况下起作用,但大约在7年前编写,并没有考虑到O.S.已经改变。太多了解有关它的细节以及为什么它对我不起作用。

我试图解决的主要问题是我的原始拖放代码使用旧学校的方式在拖放操作的GiveFeedback事件中绘制新光标。除了在触摸设备上工作得很好,因为Windows O.S.在触摸拖动操作期间隐藏光标,因此我的自定义绘制光标将永远不会显示。一些(用于轻微)谷歌搜索显示,即使调用本机ShowCursor方法,Windows也不允许两个指针设备同时处于活动状态。很公平。

在拖放操作中尝试在屏幕上绘图的最大问题是发送到窗口的大多数消息(例如WM_MOUSEMOVE和WM_PAINT)都被挂起。我可以绘制任何东西的唯一方法是在GiveFeedback事件中。

所以,我发现这个article涵盖了使用透明叠加层的绘图。再一次,它并没有完全符合我的要求,但通过一些调整它完美无缺。我能够抓住叠加的HDC和我的表格的HDC并做一个不错的BitBlt操作来在屏幕上显示我的自定义位图,并通过抓取窗体的底层图像来擦除旧图形。我还将绘制自定义光标的方法更改为绘制自定义位图的方法。

以下是我对上述文章所做的更改

this.BackColor = Color.White;
this.Opacity = 1;      // Tweak as desired
this.TransparencyKey = Color.White;

我添加的内容允许消息泵通过

protected override CreateParams CreateParams
    {
        get
        {
            CreateParams createParams = base.CreateParams;
            createParams.ExStyle |= Win32.WS_EX_TRANSPARENT;

            return createParams;
        }
    }

其余部分的细节并不过分复杂,但需要对拖放操作,叠加,绘图和擦除以及双缓冲进行良好的混合。还有一些情况,比如在我的情况下,我在拖动时更新了TreeView控件,我必须展开绘制操作的矩形,以便bitblt图像覆盖绘图之外的区域。

如果您对这篇文章感兴趣并想看看我做了什么以及如何完成它,请在评论中告诉我,我会发布代码。

答案 1 :(得分:0)

试试这段代码 希望对你有帮助

 public Form1()
        {
            InitializeComponent();
            TreeNode node;
            for (int x = 0; x < 3; ++x)
            {

                node = treeView1.Nodes.Add(String.Format("Node{0}", x * 4));
                for (int y = 1; y < 4; ++y)
                {

                    node = node.Nodes.Add(String.Format("Node{0}", x * 4 + y));
                }
            }

            treeView1.AllowDrop = true;
            treeView1.Dock = DockStyle.Fill;
            treeView1.ItemDrag += new ItemDragEventHandler(treeView1_ItemDrag);
            treeView1.DragEnter += new DragEventHandler(treeView1_DragEnter);
            treeView1.DragOver += new DragEventHandler(treeView1_DragOver);
            treeView1.DragDrop += new DragEventHandler(treeView1_DragDrop);
        }
        private void treeView1_ItemDrag(object sender, ItemDragEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                DoDragDrop(e.Item, DragDropEffects.Move);
            }

            else if (e.Button == MouseButtons.Right)
            {
                DoDragDrop(e.Item, DragDropEffects.Copy);
            }
        }

        private void treeView1_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = e.AllowedEffect;
        }
        private void treeView1_DragOver(object sender, DragEventArgs e)
        {
            Point targetPoint = treeView1.PointToClient(new Point(e.X, e.Y));
            treeView1.SelectedNode = treeView1.GetNodeAt(targetPoint);
        }

        private void treeView1_DragDrop(object sender, DragEventArgs e)
        {
            Point targetPoint = treeView1.PointToClient(new Point(e.X, e.Y));
            TreeNode targetNode = treeView1.GetNodeAt(targetPoint);
            TreeNode draggedNode = (TreeNode)e.Data.GetData(typeof(TreeNode));      
            if (!draggedNode.Equals(targetNode) && !ContainsNode(draggedNode, targetNode))
            {
                if (e.Effect == DragDropEffects.Move)
                {
                    draggedNode.Remove();
                    targetNode.Nodes.Add(draggedNode);
                }
                else if (e.Effect == DragDropEffects.Copy)
                {
                    targetNode.Nodes.Add((TreeNode)draggedNode.Clone());
                }

                targetNode.Expand();
            }
        }

        private bool ContainsNode(TreeNode node1, TreeNode node2)
        {
            if (node2.Parent == null) return false;
            if (node2.Parent.Equals(node1)) return true;
            return ContainsNode(node1, node2.Parent);
        }