My code is:

<Grid AllowDrop="True" Background="Transparent"/> 

What I see:

enter image description here

What I wish to see:

enter image description here

How to do it?

  • Icon extractedIcon = System.Drawing.Icon.ExtractAssociatedIcon (@ "FILE_PATH / PATH_K_FILE"); This is to get the icon by association in the Windows itself. But I don’t know what to do with this further, since I didn’t work with wpf. Perhaps with DragAndDrop, the cursor can simply be replaced with an icon. - Garrus_En
  • :) I'm talking about the standard mechanism. How to draw an icon when drag & drop I know. And there is a standard algorithm ( stackoverflow.com/questions/44466208/… ). - D .Stark
  • then the question is not entirely correct. We need to clarify what exactly can not be done - Garrus_En
  • 2
    those. Do you want that when you drag a file into the application window, it (the icon) takes on its original appearance? - Garrus_En
  • 3

2 answers 2

The standard mechanism is the delegation of matching an icon and its rendering to the standard Shell COM object, DragDropHelper .

There is no need for a drag-and-drop drag-and-drop object.

That is what is used when drawing the drag image in Chrome / Chromium .

The standard mechanism involves using the work with the DragDropHelper from both the source and the target side:

  • create a DragDropHelper / IDragSourceHelper from the source, set an icon through it. In your case, this makes Explorer.
  • create a DragDropHelper / IDropTargetHelper from the goal, and use it for the drawing given by the source. In the example from the question - Chrome does it, and you need to do the same.

WPF’s minimal IDropTargetHelper implementation:

 using System; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Input; using System.Windows.Interop; using IDataObject_Com = System.Runtime.InteropServices.ComTypes.IDataObject; namespace WpfApp2 { [StructLayout(LayoutKind.Sequential)] public struct Win32Point { public int x; public int y; } [ComImport] [Guid("4657278A-411B-11d2-839A-00C04FD918D0")] public class DragDropHelper { } [ComVisible(true)] [ComImport] [Guid("4657278B-411B-11D2-839A-00C04FD918D0")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IDropTargetHelper { void DragEnter( [In] IntPtr hwndTarget, [In, MarshalAs(UnmanagedType.Interface)] IDataObject_Com dataObject, [In] ref Win32Point pt, [In] int effect); void DragLeave(); void DragOver( [In] ref Win32Point pt, [In] int effect); void Drop( [In, MarshalAs(UnmanagedType.Interface)] IDataObject_Com dataObject, [In] ref Win32Point pt, [In] int effect); void Show( [In] bool show); } /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private IDropTargetHelper ddHelper = (IDropTargetHelper)new DragDropHelper(); private void Window_DragEnter(object sender, DragEventArgs e) { e.Effects = DragDropEffects.Copy; e.Handled = true; Point p = this.PointToScreen(e.GetPosition(this)); Win32Point wp; wp.x = (int)pX; wp.y = (int)pY; ddHelper.DragEnter(new WindowInteropHelper(this).Handle, e.Data as IDataObject_Com, ref wp, (int)e.Effects); } private void Window_DragOver(object sender, DragEventArgs e) { e.Effects = DragDropEffects.Copy; e.Handled = true; Point p = this.PointToScreen(e.GetPosition(this)); Win32Point wp; wp.x = (int)pX; wp.y = (int)pY; ddHelper.DragOver(ref wp, (int)e.Effects); } private void Window_DragLeave(object sender, DragEventArgs e) { e.Handled = true; ddHelper.DragLeave(); } private void Window_Drop(object sender, DragEventArgs e) { e.Effects = DragDropEffects.Copy; e.Handled = true; Point p = this.PointToScreen(e.GetPosition(this)); Win32Point wp; wp.x = (int)pX; wp.y = (int)pY; ddHelper.Drop(e.Data as IDataObject_Com, ref wp, (int)e.Effects); } } } 

XAML:

 <Window x:Class="WpfApp2.MainWindow" ... AllowDrop="True" DragEnter="Window_DragEnter" DragOver="Window_DragOver" DragLeave="Window_DragLeave" Drop="Window_Drop"> ... </Window> 

I used Shell Style Drag and Drop in .NET (WPF and WinForms) as a basis. Unfortunately, there is no code for WFP in it. Perhaps there are some subtleties specific to WFP (for example, mapping Effect -> Effects), so let me know if you need some refinement :)

  • 1. The position of the mouse must be transmitted in screen coordinates, and not relative, i.e. this.PointToScreen(e.GetPosition(this)); 2. To e.Effects = DragDropEffects.Copy; actually applied, you need to set e.Handled = true; after that e.Handled = true; - MSDN.WhiteKnight
  • @ MSDN.WhiteKnight, well, do not forget about the possible scaling in Windows, but these are trifles :) - Andrey NOP
  • @ MSDN.WhiteKnight thanks for feedback, updated code. Kopipasta, however, rolls over, but more clearly :) - PashaPash

Well, the answer @PashaPash is quite comprehensive. But, as I understand it, you are not interested in inserting icons, but getting the original one.

Having a little studied a question. That's what I got. The image itself can be obtained by regular means. Simply use e.Data.GetData ("DragImageBits"), where e is DragEventArgs.

In this case, you will get the image itself in a very primitive format. At the beginning there is a heading of 6 int in size, where the first two are width and height, the second is the point of capture by the X and Y cursor, and the last ones seem to be either MagicNumber or some kind of service info. Then comes the image itself in the BGRA format.

Code for image:

 BitmapSource bitmapSource = null; int Xpos = 0; int Ypos = 0; var stream = e.Data.GetData("DragImageBits") as MemoryStream; if(stream == null) return; using (BinaryReader reader = new BinaryReader(stream, Encoding.ASCII, true)) { // Чтение заголовка reader.BaseStream.Position = 0; int width = reader.ReadInt32(); int height = reader.ReadInt32(); Xpos = reader.ReadInt32(); Ypos = reader.ReadInt32(); // Получение исходного изображения reader.BaseStream.Position = 24; byte[] data = reader.ReadBytes(width * height * 4); PixelFormat pixelFormat = PixelFormats.Pbgra32; int stride = 4 * ((width * pixelFormat.BitsPerPixel + 31) / 32); bitmapSource = BitmapSource.Create(width, height, 96, 96, pixelFormat, null, data, stride); // Трансформация, поскольку исходное изображение перевёрнуто и отражено TransformGroup transformGroup = new TransformGroup(); transformGroup.Children.Add(new RotateTransform(180)); transformGroup.Children.Add(new ScaleTransform(-1, 1)); bitmapSource = new TransformedBitmap(bitmapSource, transformGroup); } 

As a result, you have BitmapSource - the original image with the icon and title, Xpos and Ypos - the coordinates of the point where the cursor holds the image.

How to use all this apparently will figure it out.

  • one
    Apparently, the last two numbers are handles of pictures (so as not to read bytes manually) and color, which means transparency. - structure SHDRAGIMAGE, msdn.microsoft.com/en-us/library/bb759778.aspx - PashaPash
  • @PashaPash about the handle is possible, but that's about the color does not match. In the data there is pure white without transparency (0xFFFFFFFF). Although I'm probably confusing something. - John
  • there is a semi-documented api. there should be a color in the format 0x00bbggrr. 0xFFFFFFFF most likely means that the color is not set. - PashaPash