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

时间:2014-04-03 06:37:41

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

大家早上好! 昨天我尝试在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-事件指向这三种方法。因此,我可以随意移动我对窗体的控制,就像我想要的那样。

这是棘手的一点: 我有控件的数据集可以是层次依赖,这意味着,一个控件表示另一个组件的细节,这就是我的控件具有Listbox或TreeViews的原因。为了建立这样的层次依赖,我非常希望DragDrop在我的高阶控件的列表框上的低阶控件,导致数据被传输。

我知道如何为列表框设置我的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"嘿,我,拖动' n'在这里停下来来解决这个问题!",从而添加到我的GeneralMouseDown - 方法:

this.DoDragDrop(this, DragDropEffects.Move);

这一方面,得到DragEnter - 事件要点火=>是啊!另一方面,移动部件仅在我释放鼠标后工作,导致控件永久挂在鼠标指针上=>防呀!

这里有一个问题:有没有办法,同时采取两种行动?所以我可以移动我的控制,像现在一样在每个位置查看它并在我到达另一个控件的那个区域时触发DragEnter - 事件?

2 个答案:

答案 0 :(得分:0)

移动Control会干扰自动DragDrop处理。

我建议继续使用正常的DragDrop程序,即将所有视觉效果留给系统:它将显示一个光标,指示何时输入有效目标,然后更改为指示操作的目标。

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

这是我将PictureBox拖到ListBox上的版本:

    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);
    }

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

修改 现在,如果另一方面你需要移动控件以重新排列它们,也许你应该放弃Drag& Drop来处理额外的数据传输并自己编写这部分代码。您可以使用接收控件的MouseEnter事件..

答案 1 :(得分:0)

经过一点点的努力,我做到了。我切换了处理拖动的级别。

首先,我只需要MouseDown - 事件

public Point GrabPoint;

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

我设置了抓取控件并启动DragDrop的点。在我的表单上,我处理所有拖动:

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 - 事件,因为在表单上删除任何控件时都不会发生任何事情。这样我总是在拖动时绘制我的控件=>呀!

下一部分很简单:由于我真的拖动控件,这段代码在我的列表框上执行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键来复制内容而不是删除控件。