从.Net Solution Explorer拖放时,如何以编程方式获取文件名?

时间:2019-04-03 06:32:23

标签: c# .net visual-studio winforms

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

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

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

我尝试了DataFormats的所有可能值,所有这些值都返回false。

2 个答案:

答案 0 :(得分:2)

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

Visual Studio生成的DataFormats是部分通用的(UnicodeTextText),但是实际的文件列表在非通用的(经典)MemoryStream对象中传递DataFormat CF_VSSTGPROJECTITEMS

MemoryStream包含Unicode文本-被删除的Project + File Name元组的实际列表-用竖线(|)分隔-以及其他一些我认为没有用的二进制部分在这里描述。

另一种非常见/预定义格式 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)
{
    VisualStudioDataObject vsObject = new VisualStudioDataObject(e.Data);
}

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

(已通过Visual Studio 2017测试)

using System;
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");
        }
        this.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) {
            this.SourceProject = project;
            this.FilePath = path;
            this.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":
                    this.StartingObject = data.GetData(DataFormats.UnicodeText, true).ToString();
                    break;
                case "VX Clipboard Descriptor Format":
                    var projectMS = (MemoryStream)data.GetData("VX Clipboard Descriptor Format", false);
                    projectMS.Position = 0;
                    string prjFile = Encoding.Unicode.GetString(projectMS.ToArray()).TrimEnd("\0".ToCharArray());
                    this.ProjectFilePath = prjFile;
                    this.ProjectPath = Path.GetDirectoryName(prjFile);
                    break;
                case "CF_VSSTGPROJECTITEMS":
                    GetFileData((MemoryStream)data.GetData("CF_VSSTGPROJECTITEMS", 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) {
            this.ProjectUUID = match.Value;
            content = content.Replace(this.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"));
                this.FileList.Add(new FileObject(projectFiles[i], sourceFile, Path.GetExtension(sourceFile)));
            }
        }
        else
        {
            this.FileList = null;
            throw new InvalidDataException("Invalid Data content");
        }
    }
}

答案 1 :(得分:0)

我尝试使用TreeView控件进行批准:

        Tree.AllowDrop = true;
        Tree.DragEnter += (s, e) =>
        {
            e.Effect = DragDropEffects.Move;
        };

        Tree.DragDrop += (s, e) =>
        {
            var data = e.Data;
            var value = data.GetData(typeof(string));
        };

从解决方案资源管理器中将cs文件拖放到树中后,您可以读出cs文件的路径。可用于将文件转换为zip的路径。

>>> value = "C:\\Users\\Name\\Desktop\\Projekte\\Projekte-Visual Studio\\Project\\Project\\Classes\\Method.cs"

希望有帮助。