C# 移动自己的控件并使它们可放置

本文关键字:移动 自己的 控件 | 更新日期: 2023-09-27 17:56:25

大家

早上好!昨天,我在尝试在WinForms应用程序中为自己的控件实现自定义 DragDrop 时遇到了问题。

我有一个窗体,可以动态创建我自己的两个控件的实例。这些控件由一些控件本身组成,例如按钮、标签和列表框/树视图。控件用作特定数据集的表示形式。现在,我们都知道VS中的类图。那里有这些代表类的框。您可以通过执行(我称之为)来移动画布上的框,就像拖动文件一样。为了使用我自己的控件实现此目的,我做了以下操作:

public partial class MyControl: UserControl
{
private Control activeControl;
private void GeneralMouseDown(MouseEventArgs e)
{
    activeControl = this;
    previousLocation = e.Location;
    Cursor = Cursors.Hand;   
}
private void GeneralMouseMove(Control sender, MouseEventArgs e)
{
    if (activeControl == null || activeControl != sender)
        return;
    var location = activeControl.Location;
    location.Offset(e.Location.X - previousLocation.X, e.Location.Y - previousLocation.Y);
    activeControl.Location = location;
}
private void GeneralMouseUp()
{
    activeControl = null;
    Cursor = Cursors.Default;
}
}

我想"抓取"用于拖动的控件MyControl其 MouseDown-、MouseMove- 和 MouseUp-事件指向这三个方法。因此,我可以随心所欲地在窗体上自由移动我的控件。

棘手的一点来了:我有控件的数据集可以位于分层依赖项中,这意味着一个控件表示另一个控件的组件的详细信息,这就是我的控件具有列表框或树视图的原因。为了建立这样的分层依赖关系,我非常想将低阶控件拖放到我的高阶控件的列表框中,从而导致数据传输。

我知道如何为列表框设置DragEnterDragDrop方法,就像我以前对文件所做的那样。只是为了完整起见:

private void lst_MyControl_DragEnter(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(typeof(MyControl)))
        e.Effect = DragDropEffects.Move;
    else e.Effect = DragDropEffects.None;
}

问题是:当我移动我的控件时(在每个位置都会重新绘制,产生非常想要的效果!),当我将其"拖动"到目标列表框上时,DragEnter事件不会被触发。我想我可以通过告诉Windows"嘿,我,在这里拖放!"来解决这个问题,从而添加到我的GeneralMouseDown方法中:

this.DoDragDrop(this, DragDropEffects.Move);

一方面,这会触发DragEnter事件=>是的!另一方面,移动部分仅在我释放鼠标后才起作用,导致控件永远挂在鼠标指针上=> 反是!

问题是:有没有办法同时进行两个操作?这样我就可以移动我的控件,像现在一样在每个位置抓住它,并在到达另一个控件的那个区域时触发DragEnter事件?

C# 移动自己的控件并使它们可放置

移动控件会干扰自动拖放处理。

我建议保持正常的 DragDrop 过程,即将所有视觉对象留给系统:它将显示一个光标,指示何时输入有效目标,然后更改为指示操作的光标。

您只需要 3 行,没有麻烦,用户不会看到笨重的控件四处移动。

下面是我将图片框拖到列表框上的版本:

    private void listBox1_DragEnter(object sender, DragEventArgs e)
    {
        e.Effect = DragDropEffects.Copy;
    }
    private void listBox1_DragDrop(object sender, DragEventArgs e)
    {
        listBox1.Items.Add( e.Data.GetData(DataFormats.Text));
    }
    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == System.Windows.Forms.MouseButtons.Left) 
            pictureBox1.DoDragDrop(pictureBox1.ImageLocation, DragDropEffects.Copy);
    }

显然,您将以自己的方式设置和接收数据。

编辑:现在,另一方面,如果您需要移动控件以重新排列它们,也许您应该放弃拖放来处理额外的数据传输并自行编写此部分。您可以使用接收控件的MouseEnter事件。

经过一番摆弄,我做到了。我切换了处理拖动的级别。

首先我只需要MouseDown事件

public Point GrabPoint;
private void GeneralMouseDown(MouseEventArgs e)
{
    GrabPoint = e.Location;
    this.DoDragDrop(this, DragDropEffects.Move);
}

我设置了获取控件并启动拖放的位置。在我的表格上,我处理所有拖动:

private void frmMain_DragEnter(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(typeof(MyControl1)) || e.Data.GetDataPresent(typeof(MyControl2)) || e.Data.GetDataPresent(typeof(MyControl3)))
        e.Effect = DragDropEffects.Move;
    else e.Effect = DragDropEffects.None;
}
private void frmMain_DragOver(object sender, DragEventArgs e)
{
    Point DragTarget = new Point(e.X, e.Y);
    Point GrabPoint = new Point(0, 0);
    if (e.Data.GetDataPresent(typeof(MyControl1)))
        GrabPoint = ((MyControl1)e.Data.GetData(typeof(MyControl1))).GrabPoint;
    else if (e.Data.GetDataPresent(typeof(MyControl2)))
        GrabPoint = ((MyControl2)e.Data.GetData(typeof(MyControl2))).GrabPoint;
    else if (e.Data.GetDataPresent(typeof(MyControl3)))
        GrabPoint = ((MyControl3)e.Data.GetData(typeof(MyControl3))).GrabPoint;
    DragTarget.X -= GrabPoint.X;
    DragTarget.Y -= GrabPoint.Y;
    DragTarget = this.PointToClient(DragTarget);
    if (e.Data.GetDataPresent(typeof(MyControl1)))
        ((MyControl1)e.Data.GetData(typeof(MyControl1))).Location = DragTarget;
    else if (e.Data.GetDataPresent(typeof(MyControl2)))
        ((MyControl2)e.Data.GetData(typeof(MyControl2))).Location = DragTarget;
    else if (e.Data.GetDataPresent(typeof(MyControl3)))
        ((MyControl3)e.Data.GetData(typeof(MyControl3))).Location = DragTarget;
}

目前我不需要 DragDrop -事件,因为当窗体上删除任何控件时,什么都不会发生。这样,我总是在拖动控件时绘制控件=>是的!

下一部分很简单:由于我实际上是在拖动控件,因此这段代码在我的列表框上进行了拖放处理 编辑: ListView

private void lst_SubControls_DragEnter(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(typeof(MyControl2)))
        e.Effect = DragDropEffects.Move;
    else e.Effect = DragDropEffects.None;
}
private void lst_SubControls_DragDrop(object sender, DragEventArgs e)
{
    lst_SubControls.Items.Add(((MyControl2)e.Data.GetData(typeof(MyControl2))).SpecificDrive);
    ((MyControl2)e.Data.GetData(typeof(MyControl2))).DeleteThisControl();
}

这会导致将条目添加到列表中并删除拖动的控件。此时可能会进行检查,是否按 ctrl 键复制内容而不是删除控件。