#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. Спасибо, что уделили мне время. Хотя ваше решение отлично работает для одиночных выборок, при выборе нескольких элементов отображается только файл для первого элемента. Вот почему я выбрал другое решение.