C#从listBox实现拖放

5
我正在尝试构建一个简单的界面,允许用户将文件拖放到listBox中以将它们添加到处理过程中,并可以拖出以删除它们。一切都很顺利,但我想添加一个功能,使其稍微复杂一些。
现在,我将项目的删除绑定到DragLeave事件,这意味着鼠标一离开该框,项目就被删除了。但我希望用户能够改变主意。换句话说,如果他们意识到他们正在拖出错误的文件,我希望他们能够将鼠标移回listBox并释放鼠标以取消操作。我认为这意味着我需要能够捕获MouseUp事件而不是DragLeave事件。但到目前为止,这并不成功。
下面是我当前用于删除拖出文件的代码。如何修改以保留文件直到用户松开鼠标按钮?
private void listBox1_MouseDown(object sender, MouseEventArgs e)
{
    if (listBox1.Items.Count == 0)
    { 
        return; 
    }

    int index = listBox1.IndexFromPoint(e.X, e.Y);
    string s = listBox1.Items[index].ToString();
    DragDropEffects dde1 = DoDragDrop(s, DragDropEffects.All);
}

private void listBox1_DragLeave(object sender, EventArgs e)
{
    ListBox lb = sender as ListBox;
    lb.Items.Remove(lb.SelectedItem);
}

编辑 2013/05/16

迄今为止,评论和答案都很有用,但我意识到我的问题不够清晰。在这种情况下,我正在显示一个与父表单分开的对话框,其大小基本上与listBox一样大。当有人将文件从列表中拖出时,他们完全将其拖出了表单。我是否已经陷入了困境?我认识到我正在使它比必要的更难,但如果可能的话,我仍然想看看它如何工作。


1
不要让用户通过将其拖到“ListBox”之外来删除项目,而是可以为用户创建一个拖放目标,以便将其拖动到该目标上进行删除。在这种情况下,您可以将lb.Items.Remove(lb.SelectedItem);移动到该目标控件的DragDrop事件处理程序中。 - Bolu
另一种替代方法是在 lb.Items.Remove(lb.SelectedItem); 之前提供一个警告 messagebox,以便与用户进行双重确认。 - Bolu
在你的表单上放置一个垃圾桶图标。现在,对于你的用户和代码来说都很清晰明了。 - Hans Passant
@HansPassant,我尝试过这个方法,但是无法使DragDrop事件起作用。我使用了与上面相同的事件处理程序,但没有任何反应。 - tmoore82
@Bolu,谢谢!两个好建议。我修改了我的问题以澄清我的目标,但这是一个很好的临时解决方案。 - tmoore82
1个回答

6

这里是一种比较快捷的方法来实现您想要的功能:

public object lb_item = null;



private void listBox1_DragLeave(object sender, EventArgs e)
{
    ListBox lb = sender as ListBox;

    lb_item = lb.SelectedItem;
    lb.Items.Remove(lb.SelectedItem);
}

private void listBox1_DragEnter(object sender, DragEventArgs e)
{       
    if (lb_item != null)
    {
        listBox1.Items.Add(lb_item);
        lb_item = null;
    }
}


private void listBox1_MouseDown(object sender, MouseEventArgs e)
{
    lb_item = null;

    if (listBox1.Items.Count == 0)
    {
        return;
    }                

    int index = listBox1.IndexFromPoint(e.X, e.Y);
    string s = listBox1.Items[index].ToString();
    DragDropEffects dde1 = DoDragDrop(s, DragDropEffects.All);      
}

private void Form1_DragDrop(object sender, DragEventArgs e)
{            
    lb_item = null;
}

每次用户将一个项目拖出盒子时,该项目会被临时保存,直到用户将其放在其他地方或鼠标按下列表中的新项目。 注意重要的部分是检测用户何时以及在何处释放鼠标,这是处理Form1的DragDrop事件的原理,Form1是listBox1的父级。
根据布局的复杂程度和密度,您处理DragDrop的位置可能会有很大的不同。 这就是为什么它有点“hacky”的原因,但它也非常简单。 不过,null lb_item 的位置应该无关紧要,因为它只与特定的ListBox相关。
我想另一种方法是跟踪用户的鼠标状态并相应地采取行动,如果处理大量DragDrop事务是不可行的,那么这种方法可能更合适。
编辑:如果您想要真正彻底,可以使用foreach枚举基本表单上的每个控件,并编程附加DragDrop事件的处理程序,然后在完成后删除它...但那可能有点疯狂。 我相信有人有更好的方法。

太棒了,@glace!谢谢!全局变量是一个很好的补充和我缺失的关键部分。我更新了我的问题以澄清我的目标。如果我将它从表单上拖出去怎么办?我只需将DragEnter事件处理程序添加到整个表单中吗? - tmoore82
嗯...我不确定。试试看,摆弄一下,看看事件是否被触发。肯定有办法解决这个问题,我很惊讶为什么没有其他人提出更好的解决方案。 - B L
1
您的解决方案使我能够在表单上拖放,而且无需进行任何更改。谢谢! - tmoore82

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接