Winform窗体实现拖放功能DragDrop,获取拖拽的文件路径,管理员权限下拖放失效问题

539 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第31天,点击查看活动详情

拖放功能(两种方式)

Winform窗体中控件属性AllowDrop表示允许拖放,通过启用它,可以实现将文件或数据直接拖入到窗体(控件)的功能。

DragDrop事件则用来处理拖入的数据。

但是,仅设置AllowDrop = true并不会触发DragDrop事件,DragEnter是会触发的。

要想触发DragDrop事件,需要在DragEnter事件方法中设置DragEventArgs参数的Effect属性,e.Effect表示拖放操作中目标放置的效果。e.Effect默认值为DragDropEffects.None,没有任何拖入放置的效果,控件不接受拖入的对象,则DragDrop无法触发。

e.Effect仅表示放入的效果,无效果不接受拖放;其他任何取值仅表示显示的光标效果,不影响拖放和获取数据。

如果对拖动操作使用自定义的光标效果,请参阅 GiveFeedbackEventArgs.UseDefaultCursors

因此,WInform实现拖放功能的设置如下:

  • AllowDrop = true:允许拖放

  • DragEnter事件中设置e.Effect为非None,接受拖入的对象

  • DragDrop事件中处理拖入的数据及操作

因此,可以看到直接在DragEnter处理拖放也是一样的。

  • AllowDrop = true:允许拖放
  • DragEnter事件中处理拖入的数据及操作(设置e.Effect为非必须)

Winform窗体启用拖拽后,拖放到窗体内的控件上一样有效。

除了上面两个事件,还有DragOver、DragLeave,以及QueryContinueDrag(在拖放期间放生,允许拖动源是否取消拖放操作)。

获取拖入文件或文件夹的路径

使用DragDrop

AllowDrop = true;
DragEnter += Form1_DragEnter;
DragDrop += Form1_DragDrop;

DragEnter事件中使用e.Data.GetDataPresent判断拖入的数据格式。如下,判断是文件拖放,则设置DragDropEffects效果。

private void Form1_DragEnter(object sender, DragEventArgs e)
{
    // 判断拖拽的数据格式
    if (e.Data.GetDataPresent(DataFormats.FileDrop))
        e.Effect = DragDropEffects.Link;
    else
        e.Effect = DragDropEffects.None;
}
private void Form1_DragDrop(object sender, DragEventArgs e)
{
    string path = ((Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString();
    InitialFileOrDir(path); // 处理文件
}

仅使用DragEnter

AllowDrop = true;
DragEnter += Form1_DragEnter;

// ............

private void Form1_DragEnter(object sender, DragEventArgs e)
{
    // 判断拖拽的数据格式
    if (e.Data.GetDataPresent(DataFormats.FileDrop)) { 
        e.Effect = DragDropEffects.Link;
        string path = ((Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString();
        // 处理文件或文件夹path...
    }
    else
        e.Effect = DragDropEffects.None;
}

获取拖入的多个文件

private void Form1_DragEnter(object sender, DragEventArgs e)
{
    // 判断拖拽的数据格式
    if (e.Data.GetDataPresent(DataFormats.FileDrop)) // 处理文件拖放
    {
        e.Effect = DragDropEffects.Link;
        // 多个文件
        var files = (string[])e.Data.GetData(DataFormats.FileDrop);
        
    }
    else
        e.Effect = DragDropEffects.None;
}

管理员权限运行时拖放文件无效的问题

从Windows Vista开始,由于用户界面权限隔离(User Interface Privilege Isolation),所以无法从一个低权限运行的程序拖放到高权限运行的程序中。

因此,如果程序以管理员权限运行,要想实现拖放,文件资源管理器也应该以管理员权限打开(事实是,Windows Explorer文件资源管理器无法提升权限)。

以管理员权限打开程序,可以Debug或者直接运行,会发现拖放无效,不起作用。

解决办法有两种:

  • 禁用UAC,不使用管理员权限运行
  • 使用另外的文件管理器,以管理员权限打开。然后使用其进行拖拽

以管理员权限打开(文件)资源管理器的方法(不一定有效)

以管理员权限打开PowerShell,输入:

taskkill /f /im explorer.exe

start-process explorer.exe

或,以管理员权限打开cmd,输入:

taskkill /f /im explorer.exe

start explorer.exe

另,似乎 在资源管理器的选项中,设置 Launch folder windows in a separate process,然后关闭所有的文件夹后,再次打开也可以管理员权限(也似乎不一定起作用,应该和Windows版本有关)

参考