Как программно получить имя файла при перетаскивании из .Net Solution Explorer?

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

#c# #.net #visual-studio #winforms #перетаскивание

Вопрос:

Я хочу написать приложение, которое создает zip-файлы путем прямого перетаскивания файлов из Visual Studio Solution Explorer в мое приложение.

Я использовал следующий фрагмент кода, чтобы перехватить входящий объект DataObject:

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

Я перепробовал все возможные значения DataFormats , все они возвращают false .

Ответ №1:

Поскольку эта задача может быть несколько менее простой, чем кажется на бумаге, вот пример процедуры, которая должна позволить получить список файлов, перетаскиваемых с панели Visual Studio Solution Explorer.

DataFormats , Которые генерирует Visual Studio, частично являются общими ( UnicodeText и Text ), но фактический список файлов передается в (классическом) объекте MemoryStream, который не является общим DataFormat : CF_VSSTGPROJECTITEMS .

MemoryStream содержит текст в Юникоде — фактический список удаляемых кортежей проекта имен файлов — разделенных символом канала ( | ) — и некоторые другие двоичные разделы, которые, я думаю, не стоит описывать здесь.

Другой не распространенный / предопределенный формат, VX Clipboard Descriptor Format , также является объектом MemoryStream, но это просто строка Unicode, которая содержит название проекта.


В этом примере объединенные элементы, которые являются частью перетаскивания, организованы с использованием объекта пользовательского класса, который содержит информацию о:

  • имя и UUID проекта (ов), из которого поступают файлы,
  • путь к проекту и файлу ( .[xxx]prj ) ,
  • имя объекта, который запустил операцию перетаскивания,
  • список всех удаляемых файлов, проект, частью которого они являются, и их необработанный тип ( .cs , .vb , .h , .png и т.д.)

Выберите элемент управления, который получит удаление, и добавьте обработчики:

 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("".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(""));
                FileList.Add(new FileObject(projectFiles[i], sourceFile, Path.GetExtension(sourceFile)));
            }
        }
        else {
            FileList = null;
            throw new InvalidDataException("Invalid Data content");
        }
    }
}
  

Комментарии:

1. Большое вам спасибо. Это решение идеально!

Ответ №2:

Я пытаюсь использовать элемент управления 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-файла из solution Explorer внутри дерева вы можете прочитать путь к cs-файлу. Путь, который вы можете использовать для преобразования файла в zip.

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

Надеюсь, это поможет.

Комментарии:

1. Спасибо, что уделили мне время. Хотя ваше решение отлично работает для одиночных выборок, при выборе нескольких элементов отображается только файл для первого элемента. Вот почему я выбрал другое решение.