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

2

Я хочу написать приложение, которое создает 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.

Теги:
visual-studio
winforms

2 ответа

2
Лучший ответ

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

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

MemoryStream содержит текст Unicode - фактический список отбрасываемых кортежей Project + File Name, разделенных символом канала (|), и некоторые другие двоичные разделы, которые я не считаю полезными для описания здесь.

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


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

  • название и UUID проекта (ов), откуда приходят файлы,
  • Путь к проекту и путь к файлу (.[xxx]prj),
  • имя объекта, запустившего операцию перетаскивания,
  • список всех .vb файлов, проекта, частью которого они являются, и их необработанного типа (.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");
        }
    }
}
  • 0
    Большое спасибо. Это решение идеально!
  • 0
    Я обновил код. Используйте измененный класс: он работает так же, но он определен лучше.
0

Я пытаюсь сделать это с помощью TreeView Control:

        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"

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню