【问题标题】:Performing a Drag-and-Drop operation like Windows Explorer执行拖放操作,如 Windows 资源管理器
【发布时间】:2018-08-01 09:13:19
【问题描述】:

我有一个可以拖放 SVG 文件的应用程序。这是适用于 Adob​​e XD(支持 SVG 文件)等应用程序的工具。执行基本的拖放操作非常简单。

Dim dataObj As New DataObject(DataFormats.FileDrop, New String() {_svgPath})
PictureBox.DoDragDrop(dataObj, DragDropEffects.Copy)

而且它有效!如果我想将文件拖放到资源管理器中,那么一切正常。此外,如果我将一个 .png 文件拖放到编辑器中进行绘制或将字符串拖放到编辑器:它可以工作。

现在的问题是:当涉及到其他第三方应用程序时,它会变得有点混乱。您想将 SVG 文件从您的应用程序拖放到 Adob​​e XD?不,这行不通!要将 SVG 文件从文件夹拖放到 Adob​​e XD?这将毫无问题地工作。

这种令人困惑的情况不仅出现在 Adob​​e XD 中。它们是大量其他程序,在使用资源管理器时可以使用拖放操作,但您“自己创建的”拖放操作失败。

我已经尝试了很多。用不同的数据格式、不同的 DragDropEffects 对其进行了测试……没有任何效果。就像我错过了什么。我已经在 GitHub 上搜索了不同的 DoDragDrop() 函数,在 .NET 文档中搜索只是为了查看是否缺少某些内容。

我在 System.Windows.Forms.Control 关于DoDragDrop() 函数的参考源中找到了这个:

开始拖动操作。 allowedEffects 确定可以发生哪些拖动操作。如果拖动操作需要与另一个进程中的应用程序互操作,则数据应该是基本托管类(字符串、位图或元文件)或实现 System.Runtime.Serialization.ISerializable 的某个对象。 data 也可以是任何实现 System.Windows.Forms.IDataObject 的对象。

但这些信息也没有真正的帮助。

windows 资源管理器如何创建它的 DragDrop 操作以及如何在 .Net 中进行这样的 DragDrop 操作(如果它在 vb.net 或 c# 中无关)?我需要对 DataObject 做更多的事情吗?改造它?改一下?

【问题讨论】:

  • 由于您的DataObject 是一个字符串数组,您不需要使用自定义ISerializable 对象。尝试提升您的DragDropEffectpictureBox1.DoDragDrop(dataObj, (DragDropEffects.All | DragDropEffects.Link));。请注意_svgPath 必须是完全合格的路径。这适用于 PhotoShop(已测试)。
  • @Jimi 谢谢你的提示,但我已经试过了。有趣的是,如果您使用电子白板,那么您将有相同的行为。如果您通过资源管理器将文件复制到剪贴板,那么就我而言,您可以毫无问题地将其粘贴到 Adob​​e XD 中。也许 DataObject 是问题所在。我可以尝试将数据作为字节数组添加到 MemoryStream 并将 MemoryStream 传递给 SetData 方法。
  • 是的,DragDrop DataObject 可以是 MemoryStream。但这里不应该需要它。当然,如果该程序从 DragDrop 结果中接受此输入(字符串数组 -> 文件路径)。您是否尝试过使用 PhotoShop 或您正在使用的 WebBrowser?我在两者上都测试了多文件拖放(WB 是 FireFox),并且都接受了拖放并显示位图。自己测试一下。如果它不起作用,则在您的代码中还有其他需要验证的内容。如果它有效,那么 Adob​​e XD 就有点挑剔了,你必须找出原因(我没有)。
  • 我突然想到我发布了一个小项目,用于测试来自 WebBrowser 控件(或其他任何东西)的Drag&Drop 结果。您可以从here 下载它。也许它可以帮助确定当您删除 DataObject 内容时会发生什么。
  • @Jimi 感谢您提供的信息。是的,它在 Windows 资源管理器和我自己的应用程序之间有很大的不同。我在 Twitter here 上上传了一个屏幕截图 - 好吧,我想我会尝试一下 MemoryStream 可以做什么

标签: .net vb.net winforms drag-and-drop


【解决方案1】:

这些是涉及DataFormats.FileDrop 数据类型的Drag&Drop 操作的基本要求。
如果源文件类型受 Windows GDI 相关方法(主要是BitBlt)支持,则包括源文件的缩略图。

Drag&Drop 操作开始时- 将鼠标拖到PictureBox 上- 原始.svg 文件路径被添加到专门的StringCollection 类中。
然后StringCollection 路径包含在DataObject 集合中,使用DataObject.SetFileDropList() 方法传递给DoDragDrop 方法,以及DragDropEffects 的扩展选择(根据需要设置)。

此处使用的SVGImagePath 字段指的是原始.svg 文件路径。

使用 PhotoShop、FireFox、Windows Paint、Visual Studio 图像编辑器测试的 Win GDI 图像源 (Jpeg)。
.svg 使用 FireFox 和 Edge 测试的图像。

.Net Version: 4.7.1
Visual Studio version: 15.7.5

Imports System.Collections.Specialized

Private SVGImagePath As String = "[Source SVG File]"

Private Sub PictureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseMove
    If sender IsNot Nothing AndAlso (e.Button = MouseButtons.Left) Then

        Dim dataObject As New DataObject()
        Dim FilePathsItems As New StringCollection()
        FilePathsItems.Add(SVGImagePath)

        Dim thumbCallback As Image.GetThumbnailImageAbort =
            Function()
                Return False
            End Function
        dataObject.SetImage(New Bitmap(PictureBox1.Image.GetThumbnailImage(64, 64, thumbCallback, IntPtr.Zero)))
        dataObject.SetFileDropList(FilePathsItems)
        PictureBox1.DoDragDrop(dataObject, (DragDropEffects.Copy Or DragDropEffects.Link))
    End If
End Sub

C#原码:

using System.Collections.Specialized;

private string SVGImagePath = string.Empty;

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        //Image.GetThumbnailImageAbort thumbCallback = new Image.GetThumbnailImageAbort(ThumbnailCallback);
        //FilePathsItems.Add(((FileInfo)listBox1.SelectedItem).FullName);
        DataObject dataObject = new DataObject();
        StringCollection FilePathsItems = new StringCollection();
        FilePathsItems.Add(SVGImagePath);

        Image.GetThumbnailImageAbort thumbCallback = ()=> { return false; };
        dataObject.SetImage(new Bitmap(pictureBox1.Image.GetThumbnailImage(64, 64, thumbCallback, IntPtr.Zero)));
        dataObject.SetFileDropList(FilePathsItems);
        pictureBox1.DoDragDrop(dataObject, (DragDropEffects.Copy | DragDropEffects.Link));
    }
}

【讨论】:

  • 哇,感谢您的努力,但这并不能解决我的问题。如果有变化,我还检查了您的“拖放结果工具”。输出还是一样的。我已经尝试了别的东西。我尝试保留数据格式,将数据作为字节数组添加到 MemoryStream 并将 MemoryStream 传递给 SetData 方法。也许然后我得到了与其他程序(如 Adob​​e XD)进行 D&D 操作所需的 MemoryStream Meta Infos(如果它只是简单的 Bitmap FileDrop,它似乎会检查此信息并忽略该文件)。
  • 好吧,只是那个程序不接受 Drop 看起来很奇怪。您是否使用至少一个 WebBrowser(接受 .svg 文件)对其进行了测试? (顺便说一句,你在PictureBox 中显示的是什么图像?)。此外,与文件相关的D&D 通常不会传输实际数据。如果您选择删除了一些 Gigs 文件怎么办?您只传输参考文献。
  • 我的问题中提到的旧功能已经适用于 WebBrowser。 PictureBox 显示将被拖动的图像。 “文件的演出”是什么意思?我猜有些应用程序会监听诸如“FileGroupDescriptor”、“DragContext”、“FileContents”或类似的元信息。我尝试以某种方式在 D&D 操作的对象中添加此信息。也许我需要使用 COM 接口。
  • gigs = Gigabytes。如果您从资源管理器文件中选择 20Gb,您如何将它们放入内存中?你没有。 Explorer(以及其他所有内容)只需将引用(路径)添加到DataObjectPictureBox 图像:PictureBoxes 不支持 .svg 格式(GDI 不支持)。你在那里展示什么?替代图片?
  • 它显示 .svg 的 .png。我只想利用 MemoryStream 来获取元信息。也许它有效。但我还没有找到解决方案。 Windows 资源管理器在拖放过程中包含更多信息,然后普通 DataObject 可以处理。您可以在我已经向您展示的屏幕截图中看到它。 here又来了。
【解决方案2】:

Jimi 的回答是正确的。我在 Jimi 的代码中的问题是缩略图的生成。您的目标应用程序可能会因此而阻止 D&D 操作。如果您等待几秒钟(也许GetThumbnailImage 慢慢来),那么目标应用程序将允许该文件。我留下我的个人代码作为答案。

Dim dataObj As New DataObject
Dim filePaths = New List(Of String) From {New System.IO.FileInfo(_svgPath).FullName}
Dim sc = New System.Collections.Specialized.StringCollection()
sc.AddRange(filePaths.ToArray())
dataObj.SetFileDropList(sc)
PictureBox.DoDragDrop(dataObj, DragDropEffects.Copy)

再一次:特别感谢@Jimi 的努力

【讨论】:

  • 这正是我在描述中所写的 (...) 将原始 .svg 文件路径添加到专门的 StringCollection 类中。 (...)。在代码中:Dim FilePathsItems As New StringCollection() FilePathsItems.Add(SVGImagePath)。这就是您将文件路径添加到 DataObject 集合的方式。你没看我发的内容吧?
  • @Jimi 哦抱歉我已经忘记了。我仍然试图找出为什么它现在有效。也许它有效,因为我像这样将文件添加到 StringCollection:New System.IO.FileInfo(_svgPath).FullName - 我将编辑我的答案。
  • 您总是添加完全限定路径,而不是相对路径或使用somepart & someotherpart & filename 构建的路径。在这种情况下使用Path.Combine()FileInfo().FullName 只是一个报告完全限定文件路径 (c:\Something\Somethingelse\FileName) 的字符串。这就是您始终必须做的事情。
  • @Jimi 好的,那么这也不是真正的解决方案,因为我只使用完整的文件路径(否则我会有一些其他问题哈哈)。我会拿走你的代码,看看我需要修改什么才能让它工作。
  • @Jimi 再次检查并接受了您的回答。我还更新了我的答案,说明您的代码对我不起作用的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多