c# - 从 .Net 解决方案资源管理器拖放时如何以编程方式获取文件名?

标签 c# .net visual-studio winforms drag-and-drop

我想编写一个应用程序,通过直接将文件从 Visual Studio 解决方案资源管理器拖放到我的应用程序中来生成 zip 文件。

我使用以下代码片段来捕获传入的 DataObject:

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

我已经尝试了DataFormats的所有可能值,它们都返回 false。

最佳答案

由于此任务可能不像纸面上看起来那么简单,因此这里有一个示例过程,应该允许获取从 Visual Studio 解决方案资源管理器面板拖动的文件的列表。

DataFormats Visual Studio 生成的文件部分是常见的( UnicodeTextText ),但实际的文件列表是在(经典)MemoryStream 对象中传递的,该对象不是常见的 DataFormat 。 :<强>CF_VSSTGPROJECTITEMS

MemoryStream 包含 Unicode 文本 - 正在删除的项目+文件名元组的实际列表 - 由管道 ( | ) 符号分隔 - 以及我认为描述起来没有用的一些其他二进制部分在这里。

其他非常见/预定义格式, VX Clipboard Descriptor Format ,也是一个 MemoryStream 对象,但它只是一个包含项目名称的 Unicode 字符串。


在此示例中,作为 Drop 一部分的组合元素是使用自定义类对象进行组织的,该对象包含以下信息:

  • 文件来源项目的名称和 UUID,
  • 项目路径和文件路径 ( .[xxx]prj ),
  • 启动拖放操作的对象的名称,
  • 所有已删除文件的列表、它们所属的项目及其原始类型( .cs.vb.h.png 等)

选择一个将接收 Drop 的控件并添加处理程序:

private void ctlVSDrop_DragEnter(object sender, DragEventArgs e)
{
    if (e.Data.GetFormats().Contains("CF_VSSTGPROJECTITEMS"))
    {
        e.Effect = DragDropEffects.Copy;
    }
}

private void ctlVSDrop_DragDrop(object sender, DragEventArgs e)
{
    var vsObject = new VisualStudioDataObject(e.Data);
}

类对象, VisualStudioDataObject ,包含从 DataObject 中提取信息所需的方法。由 DragDrop 引用事件DragEventArgs :

(使用 Visual Studio 2017 测试)

using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;

class VisualStudioDataObject
{
    public VisualStudioDataObject(IDataObject data)
    {
        if (data is null) {
            throw new ArgumentNullException("IDataObject data", "Invalid DataObject");
        }
        FileList = new List<FileObject>();
        GetData(data);
    }

    public List<FileObject> FileList { get; private set; }
    public string ProjectUUID { get; private set; }
    public string ProjectPath { get; private set; }
    public string ProjectFilePath { get; private set; }
    public string StartingObject { get; private set; }

    public class FileObject
    {
        public FileObject(string project, string path, string type) {
            SourceProject = project;
            FilePath = path;
            FileType = type;
        }
        public string SourceProject { get; }
        public string FilePath { get; }
        public string FileType { get; }
    }

    private void GetData(IDataObject data)
    {
        List<string> formats = data.GetFormats(false).ToList();
        if (formats.Count == 0) return;

        foreach (string format in formats) {
            switch (format) {
                case "UnicodeText":
                    StartingObject = data.GetData(DataFormats.UnicodeText, true).ToString();
                    break;
                case "VX Clipboard Descriptor Format":
                    var projectMS = (MemoryStream)data.GetData(format, false);
                    projectMS.Position = 0;
                    string prjFile = Encoding.Unicode.GetString(projectMS.ToArray()).TrimEnd("\0".ToCharArray());
                    ProjectFilePath = prjFile;
                    ProjectPath = Path.GetDirectoryName(prjFile);
                    break;
                case "CF_VSSTGPROJECTITEMS":
                    GetFileData((MemoryStream)data.GetData(format, false));
                    break;
            }
        }
    }

    private void GetFileData(MemoryStream ms)
    {
        string uuidPattern = @"\{(.*?)\}";
        string content = Encoding.Unicode.GetString(ms.ToArray());
        //Get the Project UUID and remove it from the data object
        var match = Regex.Match(content, uuidPattern, RegexOptions.Singleline);
        if (match.Success) {
            ProjectUUID = match.Value;
            content = content.Replace(ProjectUUID, "").Substring(match.Index);

            //Split the file list: Part1 => Project Name, Part2 => File name
            string[] projectFiles = content.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < projectFiles.Length; i += 2) {
                string sourceFile = projectFiles[i + 1].Substring(0, projectFiles[i + 1].IndexOf("\0"));
                FileList.Add(new FileObject(projectFiles[i], sourceFile, Path.GetExtension(sourceFile)));
            }
        }
        else {
            FileList = null;
            throw new InvalidDataException("Invalid Data content");
        }
    }
}

关于c# - 从 .Net 解决方案资源管理器拖放时如何以编程方式获取文件名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55488495/

相关文章:

c# - 如何使用 C# 从服务器获取打印机详细信息

c# - 我可以使用 zxing 生成 code_128 条码图像吗?

c# - 如何在用户控件中添加 Canvas xaml资源

.NET 异步/等待任务在没有等待的情况下运行

c# - 提交表单总是调用 get 操作方法而不是 post 操作方法

.net - 有没有办法将从 OpenCover 生成的代码覆盖率指标检索回 Jenkins?

c# - MVC 3 模型验证问题——疏忽或设计使然

c++ - VS2013 : compiler bug with float and/EHa +/fp:strict?

c# - 转换为 Azure 移动服务的 Web API 未序列化所有属性

.net - T4 工具箱 - 当前程序集中的引用类