.NET 拖放;显示拖动的边框或图像,例如 Windows do

.NET Drag and drop ; Show dragged borders or image such as Windows do

我想知道是否有办法(总有办法)或者最好的方法是什么来显示我的控件的边框或用户当前正在拖放的图像?我只从我自己的应用程序中拖动,而不是从桌面拖动。

我想要类似的东西:

我曾经尝试手动画线 "fake" 事实上这是我的控件的边框并且它工作正常......但是我很难将它们显示在其他表单的控件上,因为这是一个巨大的具有多级控件的表单。

我无法真正展示我目前拥有的代码,因为它太大了。但是,也许如果你知道一些很好的例子来执行这个我可以基于我的搜索。因为到目前为止,我找不到任何方法来在拖放时显示控件边框或控件图像。

正如您所说,这是可能的,但不是一两行..

这是一个使用 Panel dragFrame 的示例,其中显示了拖动控件的 Image

是随着光标移动,但不应在其下方滑动,因此 DragEnter 事件仍然识别光标进入。

我通过设置两个控件列表来准备表单:可以拖动的控件和可以放置的控件。但是对于示例,我只为一个目标编写代码..

我们不能在拖动期间使用 MouseMove 事件,因此我们需要使用 Timer 的解决方法。在它的 Tick 中,我们要么跟随面板,要么,如果现在鼠标按钮已经被释放,我们将中止一切。

首先我们创建面板并隐藏它。计时器应该很快..

public Form1()
{
    InitializeComponent();
    dragFrame.Visible = false;
    dragFrame.BorderStyle = BorderStyle.FixedSingle;
    Controls.Add(dragFrame);
    timer1.Interval = 20;
}

现在我们加载两个列表:

private void Form1_Load(object sender, EventArgs e)
{
    foreach (Control ctl in Controls) if (ctl != dropPanel) draggables.Add(ctl);
    makeDraggable(draggables);
    dragTargets.Add(dropPanel);
}

List<Control> dragTargets = new List<Control>();
List<Control> draggables = new List<Control>();
Panel dragFrame = new Panel();
Point mDown = Point.Empty;

此函数向可拖动控件添加了几个处理程序。涉及最多的是Mousedown。除了启动 Draggin 之外,我们还为面板创建一个新的 BackgroundImage 并调整大小并显示它。我们也开始计时。

void makeDraggable(List<Control> draggables)
{
    foreach (Control ctl in draggables)
    {
        ctl.MouseDown += (s, e) => 
            {
                mDown = e.Location;
                timer1.Start();
                dragFrame.Size = ctl.Size;

                if (dragFrame.BackgroundImage != null)
                    dragFrame.BackgroundImage.Dispose();
                Bitmap bmp = new Bitmap(dragFrame.ClientSize.Width,
                                        dragFrame.ClientSize.Height);
                ctl.DrawToBitmap(bmp, dragFrame.ClientRectangle);
                dragFrame.BackgroundImage = bmp;

                dragFrame.BringToFront();
                dragFrame.Show();
                ctl.DoDragDrop(ctl.Text, DragDropEffects.Copy | DragDropEffects.Move);
            };

        ctl.MouseUp += (s, e) =>
            {
                dragFrame.Hide();
                timer1.Stop();
            };

        ctl.Leave += (s, e) =>
        {
            dragFrame.Hide();
            timer1.Stop();
        };
    }
}

这些是一个放置目标的事件。您将需要编写处理数据的实际放置代码..

private void dropPanel_DragEnter(object sender, DragEventArgs e)
{

    if (e.Data.GetDataPresent(DataFormats.Text))
            { e.Effect = DragDropEffects.Copy;            }
    else  { e.Effect = DragDropEffects.None; }
}

private void dropPanel_DragDrop(object sender, DragEventArgs e)
{
    dragFrame.Hide();
    timer1.Stop();
}

在 timer.Tick 中,我们进行移动,并在必要时中止操作:

private void timer1_Tick(object sender, EventArgs e)
{


    if ( (Control.MouseButtons & MouseButtons.Left) == MouseButtons.None)
    {
        dragFrame.Hide();
        timer1.Stop();
    }

    if (dragFrame.Visible)
    {
        Point pt = this.PointToClient(Cursor.Position);
        dragFrame.Location = new Point(pt.X - mDown.X, 
                                       pt.Y - dragFrame.Height);
        foreach( Control ctl  in dragTargets)
            if (ctl.ClientRectangle.Contains(pt ) )
            {
                dragFrame.Hide();
            }
    }
}

如您所见,它涉及并且可能有一些怪癖。

仍然确定你需要这个吗?

最后,这是我们最终如何让它按我们想要的方式工作;

public Sub CreateCustomCursor(ByVal e As MouseEventArgs)
    Dim bmp As New Bitmap(Me.Width, Me.Height)
    ' ME IS A USERCONTROL '
    Me.DrawToBitmap(bmp, New Rectangle(New Point(0, 0), Me.Size))

    ' MAKE A CURSOR WITH AN IMAGE OF ME, WHICH IS A USERCONTROL '
    Dim cur As Cursor = Me.CreateCursor(bmp, e.X, e.Y)
    Cursor.Current = cur
    Me.IsCursorSet = True
End Sub

Public Structure IconInfo
    Public fIcon As Boolean
    Public xHotspot As Integer
    Public yHotspot As Integer
    Public hbmMask As IntPtr
    Public hbmColor As IntPtr
End Structure

<DllImport("user32.dll")> _
Public Shared Function GetIconInfo(ByVal hIcon As IntPtr, ByRef pIconInfo As IconInfo) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

<DllImport("user32.dll")> _
Public Shared Function CreateIconIndirect(ByRef icon As IconInfo) As IntPtr
End Function

private Function CreateCursor(ByVal bmp As Bitmap, ByVal xHotSpot As Integer, ByVal yHotSpot As Integer) As Cursor
    Dim ptr As IntPtr = bmp.GetHicon()
    Dim tmp As New IconInfo()
    GetIconInfo(ptr, tmp)
    tmp.xHotspot = xHotSpot
    tmp.yHotspot = yHotSpot
    tmp.fIcon = False
    ptr = CreateIconIndirect(tmp)
    Return New Cursor(ptr)
End Function