c# - 如何将文件拖放到应用程序中?




winforms drag-and-drop (8)

在Windows窗体中,设置控件的AllowDrop属性,然后监听DragEnter事件和DragDrop事件。

DragEnter事件触发时,将参数的AllowedEffect设置AllowedEffect none(例如e.Effect = DragDropEffects.Move )。

DragDrop事件触发时,你会得到一个字符串列表。 每个字符串都是要删除的文件的完整路径。

我已经在Borland的Turbo C ++环境中看到了这一点,但我不确定如何为我正在开发的C#应用​​程序做些什么。 是否有最佳做法或陷阱需要注意?


一些示例代码:

  public partial class Form1 : Form {
    public Form1() {
      InitializeComponent();
      this.AllowDrop = true;
      this.DragEnter += new DragEventHandler(Form1_DragEnter);
      this.DragDrop += new DragEventHandler(Form1_DragDrop);
    }

    void Form1_DragEnter(object sender, DragEventArgs e) {
      if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy;
    }

    void Form1_DragDrop(object sender, DragEventArgs e) {
      string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
      foreach (string file in files) Console.WriteLine(file);
    }
  }

另一个常见问题是您可以忽略Form DragOver(或DragEnter)事件。 我通常使用Form的DragOver事件来设置AllowedEffect,然后使用特定控件的DragDrop事件来处理丢弃的数据。


你需要知道一个问题。 任何在拖放操作中作为DataObject传递的类都必须是Serializable。 所以如果你尝试传递一个对象,但它不起作用,请确保它可以被序列化,因为这几乎肯定是问题所在。 这让我抓住了几次!


Judah Himango和Hans Passant的解决方案可以在Designer中使用(我目前使用VS2015):


这是我用来删除文件和/或文件夹的东西。 在我的情况下,我只是筛选*.dwg文件,并选择包含所有子文件夹。

fileList是一个IEnumerable或类似的在我的情况下绑定到一个WPF控件...

var fileList = (IList)FileList.ItemsSource;

有关该技巧的详细信息,请参阅https://.com/a/19954958/492 。

Drop Handler ...

  private void FileList_OnDrop(object sender, DragEventArgs e)
  {
    var dropped = ((string[])e.Data.GetData(DataFormats.FileDrop));
    var files = dropped.ToList();

    if (!files.Any())
      return;

    foreach (string drop in dropped)
      if (Directory.Exists(drop))
        files.AddRange(Directory.GetFiles(drop, "*.dwg", SearchOption.AllDirectories));

    foreach (string file in files)
    {
      if (!fileList.Contains(file) && file.ToLower().EndsWith(".dwg"))
        fileList.Add(file);
    }
  }

注意windows vista / windows 7的安全权限 - 如果您以管理员身份运行Visual Studio,当您从Visual Studio中运行它时,将无法将文件从非管理员资源管理器窗口拖到程序中。 与拖拽相关的事件甚至不会发射! 我希望这能帮助别人不浪费他们一生的时间......


与前面的答案一样,但是有一个很短的添加,它允许使用所有控件属性而不会出现跨线程调用异常。

帮助者方法

/// <summary>
/// Helper method to determin if invoke required, if so will rerun method on correct thread.
/// if not do nothing.
/// </summary>
/// <param name="c">Control that might require invoking</param>
/// <param name="a">action to preform on control thread if so.</param>
/// <returns>true if invoke required</returns>
public bool ControlInvokeRequired(Control c, Action a)
{
    if (c.InvokeRequired) c.Invoke(new MethodInvoker(delegate
    {
        a();
    }));
    else return false;

    return true;
}

样例用法

// usage on textbox
public void UpdateTextBox1(String text)
{
    //Check if invoke requied if so return - as i will be recalled in correct thread
    if (ControlInvokeRequired(textBox1, () => UpdateTextBox1(text))) return;
    textBox1.Text = ellapsed;
}

//Or any control
public void UpdateControl(Color c, String s)
{
    //Check if invoke requied if so return - as i will be recalled in correct thread
    if (ControlInvokeRequired(myControl, () => UpdateControl(c, s))) return;
    myControl.Text = s;
    myControl.BackColor = c;
}




c# winforms drag-and-drop