Reputation: 253
I want to write an application that produces zip files by directly dragging and dropping files from Visual Studio Solution Explorer into my app.
I've used the following code snippet to catch the incoming DataObject:
private void lblIncludedFiles_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Copy;
}
}
I've tried every possible value of DataFormats
, all of them return false.
Upvotes: 2
Views: 1056
Reputation: 32248
Since this task might be somewhat less simple than it looks like on paper, here's a sample procedure that should allow to get a list of the files dragged from the Visual Studio Solution Explorer panel.
The DataFormats
that Visual Studio generates are partially common (UnicodeText
and Text
), but the actual file list is passed on in a (classic) MemoryStream object that is not a common DataFormat
: CF_VSSTGPROJECTITEMS
.
The MemoryStream contains Unicode text - the actual list of the Project+File Name tuples that are being dropped - separated by a pipe (|
) symbol - and some other binary sections that I don't think is useful to describe here.
The other non common/predefined format, VX Clipboard Descriptor Format
, is also a MemoryStream object, but it's just an Unicode string that contains the Project name.
In this sample, the combined elements that are part of the Drop are organized using a custom class object that contains informations about:
.[xxx]prj
) ,.cs
, .vb
, .h
, .png
etc.)Pick a control that will receive the Drop and add the handlers:
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);
}
The class object, VisualStudioDataObject
, contains the methods needed to extract the informations from the DataObject
referenced by the DragDrop
event DragEventArgs
:
(Tested with 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");
}
}
}
Upvotes: 4
Reputation: 2392
I try you approch out with a 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));
};
After drop a cs-File from the solution explorer inside the tree, you can read out the path of the cs-File. The path you can use to convert the file to zip.
>>> value = "C:\\Users\\Name\\Desktop\\Projekte\\Projekte-Visual Studio\\Project\\Project\\Classes\\Method.cs"
Hope it helps.
Upvotes: 0