【问题标题】:Drag'n Drop : tell the sender when drop occursDrag'n Drop : 告诉发送者什么时候丢弃
【发布时间】:2017-01-19 19:50:28
【问题描述】:

我正在使用 c# 3.5 / winforms

在我的表单上,我在一个面板中有 2 个图片框 PB1 和 PB2(以及许多其他控件)。 用户可以拖动 PB1 到 PB2。但他也可以通过在表单上或表单外的任意位置释放左键来取消放置。 PB1 可以拖动固定次数。当拖动开始时,我在 PB1 中减少一个变量,如果它达到 0,则 PB 变得不可见。

但是如果用户取消拖动,PB1必须知道要增加变量并设置PB1的可见性。

我的问题是:PB1 如何知道何时取消拖动(或实际上,丢弃,即使在有效控件上)?请记住,用户可以在表单之外释放拖动,因此我不能在表单上使用 Drop 事件。我尝试了 GiveFeedback 和 QueryContinueDrag 事件,但只要拖动继续,它们就会被触发,但停止时不会触发。

一些代码:

class COPGOJetonImage
{
    private PictureBox PB1;

    public COPGOJetonImage()
    {
        PB1 = new PictureBox();
        //here I initialize PB1
        ((Control)PB1).AllowDrop = true; //in case of
        PB1.MouseDown += OnMouseDown;
    }
    public void OnMouseDown(object sender, MouseEventArgs ev)
    {
        PB1.DoDragDrop(PB1.Image, DragDropEffects.Copy);
    }
}

【问题讨论】:

  • "用户可以将 PB1 拖到 PB2。" PB2 是唯一有效的放置目标吗?如果唯一可以有效删除的位置是表单中的某个位置,那么在发生删除时减少变量可能更有意义。
  • DoDragDrop 是返回由放置目标设置的结果效果的方法
  • 实际上有1到4个有效目标。
  • 哎呀!实际上,有 1 到 4 个有效目标。当用户拖动最后一个实例时,我需要更改 PB1 的外观。因此,如果用户落在一个有效目标上,PB1 将保持(视觉上)禁用状态。但是如果他掉到其他任何地方(在表单或其他窗口或桌面上),PB1 必须显示启用外观

标签: c# winforms drag-and-drop


【解决方案1】:

"有 1 到 4 个有效目标。"

在此示例中,我们拖动 pictureBox1pictureBox2pictureBox5 是有效的放置目标。我们创建一个自定义名称的 DataObject 以在拖放操作期间封装pictureBox1。在放置目标中,如果自定义名称存在于被拖动的事物中,我们只允许放置。这确保我们只从pictureBox1 本身获得一个 DragDrop 事件,并且我们知道减少我们的放置计数器是安全的。我们可以从 DataObject 中检索 pictureBox1 并更改其状态,使其不再被删除:

public partial class Form1 : Form
{

    public Form1()
    {
        InitializeComponent();
    }

    private int DropsLeft = 5;
    private string DataFormatName = "YourUniqueDataFormatNameHere";

    private void Form1_Load(object sender, EventArgs e)
    {
        pictureBox1.MouseMove += PictureBox1_MouseMove;

        PictureBox[] pbs = new PictureBox[] { pictureBox2, pictureBox3, pictureBox4, pictureBox5 };
        foreach (PictureBox pb in pbs)
        {
            pb.AllowDrop = true;
            pb.DragEnter += Pb_DragEnter;
            pb.DragDrop += Pb_DragDrop;
        }
    }

    private void PictureBox1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            DataObject data = new DataObject(DataFormatName, pictureBox1);
            pictureBox1.DoDragDrop(data, DragDropEffects.Copy);
        }
    }

    private void Pb_DragEnter(object sender, DragEventArgs e)
    {
        if (e.Data.GetDataPresent(DataFormatName))
        {
            e.Effect = DragDropEffects.All;
        }
        else
        {
            e.Effect = DragDropEffects.None;
        }
    }

    private void Pb_DragDrop(object sender, DragEventArgs e)
    {
        DropsLeft--;

        // retrieve the data
        PictureBox pb = (PictureBox)e.Data.GetData(DataFormatName);

        if (DropsLeft == 0)
        {
            MessageBox.Show("No more drops left!");
            pb.Enabled = false;
            pb.BackColor = Color.Red; // for visual effect
        }
    }

}

【讨论】:

  • 感谢您的回答,我想我会使用它,因为它似乎不可能做我真正想做的事。其实这只是问题的一部分。用你的方法,PB2/PB5知道拖拽的来源,可以告诉拖拽完成的来源。但是如果用户在除 PB2/PB5 之外的任何地方(在窗体上或在另一个窗口或桌面上)释放拖动,则源不知道它。
  • 或者我需要这样,所以PB1可以在拖动释放之前做出反应:用户开始拖动,PB1改变它的外观(例如,PB1上的数字表示PB1可以拖动多少次,如果不能再拖动,则为禁用外观)。如果拖动对象在 PB2/PB5 上被释放,PB1 保持新的外观。但如果用户在其他任何地方发布,PB1 必须更改为旧外观。那么PB1怎么知道呢?
  • 你可以在调用DoDragDrop()之前更改PB1的外观,这很简单。创建一个bool 变量并将其设置为false,然后再开始拖动。进行有效丢弃时,切换标志。对DoDragDrop() 的调用实际上是阻塞,因此您可以在之后检查标志以了解发生了什么。
  • 谢谢!我没有意识到 DoDragDrop 正在阻塞!
猜你喜欢
  • 2013-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-29
  • 1970-01-01
  • 1970-01-01
  • 2011-12-19
  • 1970-01-01
相关资源
最近更新 更多