C# 拖动';n删除:在发生删除时通知发件人

C# 拖动';n删除:在发生删除时通知发件人,c#,winforms,drag-and-drop,C#,Winforms,Drag And Drop,我使用的是c#3.5/winforms 在我的表单中,我在一个面板中有两个PictureBoxPB1和PB2(以及许多其他控件)。 用户可以将PB1拖动到PB2。但他也可以通过释放表单上任何位置或表单外部的左按钮来取消放置。 PB1可以拖动固定次数。当拖动开始时,我减少了PB1中的一个变量,如果它达到0,PB就不可见了 但是如果用户取消拖动,PB1必须知道这一点,以增加变量并设置PB1的可见性 我的问题是:PB1如何知道何时取消了拖动(或者实际上,即使是在有效控件上,拖动也被删除)?请记住,用户

我使用的是c#3.5/winforms

在我的表单中,我在一个面板中有两个PictureBoxPB1和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);
    }
}
“有1到4个有效目标。”

在本例中,我们拖动
pictureBox1
,通过
pictureBox5
拖动
pictureBox2
是有效的拖放目标。我们使用自定义名称创建一个DataObject,以在拖放操作期间封装
pictureBox1
。在drop目标中,我们只允许在被拖动的对象中存在自定义名称时进行drop。这确保了我们只从
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
        }
    }

}
“有1到4个有效目标。”

在本例中,我们拖动
pictureBox1
,通过
pictureBox5
拖动
pictureBox2
是有效的拖放目标。我们使用自定义名称创建一个DataObject,以在拖放操作期间封装
pictureBox1
。在drop目标中,我们只允许在被拖动的对象中存在自定义名称时进行drop。这确保了我们只从
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
        }
    }

}

“用户可以将PB1拖动到PB2。”PB2是唯一有效的拖放目标吗?如果可以有效删除的唯一位置是表单中的某个位置,那么在发生删除时减少变量可能更有意义。
DoDragDrop
是一种返回由删除目标设置的结果效果的方法。实际上,有1到4个有效的target.oup!实际上,有1到4个有效目标。当用户拖动最后一个实例时,我需要更改PB1的外观。因此,如果用户落在一个有效目标上,PB1将保持(视觉)禁用状态。但是如果他在其他任何地方(窗体或其他窗口或桌面上)拖放,PB1必须显示一个启用外观“用户可以将PB1拖动到PB2”。PB2是唯一有效的拖放目标吗?如果可以有效删除的唯一位置是表单中的某个位置,那么在发生删除时减少变量可能更有意义。
DoDragDrop
是一种返回由删除目标设置的结果效果的方法。实际上,有1到4个有效的target.oup!实际上,有1到4个有效目标。当用户拖动最后一个实例时,我需要更改PB1的外观。因此,如果用户落在一个有效目标上,PB1将保持(视觉)禁用状态。但是如果他把它放在其他任何地方(在窗体或其他窗口或桌面上),PB1必须显示启用外观谢谢你的回答,我想我会用它,因为它似乎不可能实现我真正想要的。事实上,这只是问题的一部分。使用您的方法,PB2/PB5知道拖动的来源,并可以告诉来源拖动已完成。但是,如果用户在PB2/PB5之外的任何位置(窗体上、其他窗口上或桌面上)释放拖动,则源不知道。或者我需要它,以便PB1可以在释放拖动之前做出反应:用户开始拖动,PB1更改其外观(例如,PB1上的数字显示PB1可以拖动多少次,如果不能再拖动,则显示禁用的外观)。如果拖动对象在PB2/PB5上释放,PB1将保持其新外观。但是如果用户在其他任何地方释放,PB1必须更改为其旧外观。那么PB1如何知道?您可以在调用
DoDragDrop()之前更改PB1的外观
,这很简单。在开始拖动之前,创建一个
bool
变量并将其设置为
false
。进行有效拖放时,切换标志。调用
DoDragDrop()
实际上是阻塞,因此您可以在事后检查标志以了解发生了什么。谢谢!我没有意识到DoDragDrop正在阻塞!谢谢您的回答,我想我会使用它,因为它似乎不可能实现我真正想要的。实际上这只是问题的一部分。通过您的方法,PB2/PB5知道拖放的来源可以告诉源拖动已完成。但是如果用户在除PB2/PB5之外的任何位置(窗体上、其他窗口上或桌面上)释放拖动,则源不知道。或者我需要它,以便PB1可以在释放拖动之前做出反应:用户开始拖动,PB1更改其外观(例如,PB1上的数字显示PB1可以拖动多少次,如果不能再拖动,则显示禁用的外观)。如果拖动对象在PB2/PB5上释放,PB1将保持其新外观。但是如果用户在其他任何地方释放,PB1必须更改为其旧外观。那么PB1如何知道?您可以在调用
DoDragDrop()之前更改PB1的外观
,这很简单。在开始拖动之前,创建一个
bool
变量,并将其设置为
false
。在进行有效拖放时,切换标志。对
DoDragDrop()
的调用实际上是阻塞的,因此您可以稍后检查标志以查看发生了什么。谢谢!