Drag images from Chrome to WPF application
Drag images from Chrome to WPF application
Problem
I am currently experimenting a lot with WPF GUI’s to improve the usability within my applications. A lot of users use to drag & drop images from the web into a local application in order to add them to a collection. This sounds rather simple to implement. But it seems that every browser has its own behavior for drag & drop.
Drag & Drop
Although it is difficult and takes more time to implement logic via the MVVM Pattern I nearly always take this challenge to keep the separation of logic and GUI within my applications. Especially drag and drop is difficult here because it’s hard to define if drag and drop is a GUI thing or not.
I was lucky to find the Gong Drag & Drop Framework that made the implementation pretty easy and helped me a lot. Via bindings you’re able to delegate the drag & drop events to the ViewModel that only has to implement the IDropTarget Interface. My DataTemplate looks like this:
<Grid dragDrop:DragDrop.IsDragSource="False" dragDrop:DragDrop.IsDropTarget="True"
dragDrop:DragDrop.DropHandler="{Binding}">
<!-- .... -->
And here is a sample for the IDropTarget ViewModel implementation:
public class CreateCategoryViewModel : IDropTarget
{
// ....
public void DragOver(IDropInfo dropInfo)
{
dropInfo.DestinationText = "Go for it";
dropInfo.DropTargetAdorner = DropTargetAdorners.Highlight;
dropInfo.Effects = DragDropEffects.Copy;
}
public void Drop(IDropInfo dropInfo)
{
var data = dropInfo.Data as System.Windows.DataObject;
//...
var uri = GetUriFromData(data);
}
}
The Chrome dilemma
As I mentioned before the biggest problem with the drag & drop events from browsers is that every one has its own behavior. From google Chrome we will get a HTML bock inside the “dropInfo.Data” which we only have to parse to gather the image Uri.
I prepared a short code snippet that delivers the image Uri from the System.DataObject.
public Uri GetUriFromData(DataObject data)
{
string[] formats = data.GetFormats();
if (formats.Contains("text/html"))
{
object obj = data.GetData("text/html");
string html = string.Empty;
if (obj is string)
{
html = (string) obj;
}
else if (obj is MemoryStream)
{
MemoryStream ms = (MemoryStream) obj;
byte[] buffer = new byte[ms.Length];
ms.Read(buffer, 0, (int) ms.Length);
if (buffer[1] == (byte) 0) // Detecting unicode
{
html = Encoding.Unicode.GetString(buffer);
}
else
{
html = Encoding.ASCII.GetString(buffer);
}
}
Match match = Regex.Match(html, "<img.+?src=[\"'](.+?)[\"'].*?>", RegexOptions.IgnoreCase);
if (match.Success)
{
return new Uri(match.Groups[1].Value);
}
}
return null;
}