Сохранение стандартной иконки drag&drop при перетаскивании файлов из Windows Explorer

1,00
р.
Мой код:

Что я вижу:

Что я желаю видеть:

Каким образом это сделать?

Ответ
Стандартный механизм - это делегирование согласования иконки и её отрисовки стандартному COM-объекту Shell - DragDropHelper.
The drag-and-drop helper object (CLSID_DragDropHelper) is exported by the Shell to allow targets to specify the drag image while it is over the target window.
Именно он используется при отрисовке перетаскиваемого изображения в Chrome / Chromium.
Стандартный механизм подразумевает использование работу с DragDropHelper и со стороны источника, и со стороны цели:
создать DragDropHelper / IDragSourceHelper со стороны источника, через него задать иконку. В вашем случае - это делает Explorer. создать DragDropHelper / IDropTargetHelper со стороны цели, и использовать его для отрисовки, переданной источником. В примере из вопроса - это делает Хром, и это же нужно сделать вам.
Минимальная реализация IDropTargetHelper со стороны WPF:
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) }
/// /// Interaction logic for MainWindow.xaml /// 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)p.X wp.y = (int)p.Y
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)p.X wp.y = (int)p.Y
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)p.X wp.y = (int)p.Y
ddHelper.Drop(e.Data as IDataObject_Com, ref wp, (int)e.Effects) } } }
XAML:
...
Я использовал в качестве основы статью Shell Style Drag and Drop in .NET (WPF and WinForms). В ней, к сожалению, нет кода для WFP. Возможно, есть какие-то тонкости, специфические для WFP (например, маппинг Effect -> Effects), так что дайте знать, если нужна доработка :)