Страницы

Поиск по вопросам

среда, 27 ноября 2019 г.

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

#c# #wpf #drag-n-drop



Мой код:




Что я вижу:



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



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


Ответы

Ответ 1



Стандартный механизм - это делегирование согласования иконки и её отрисовки стандартному 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), так что дайте знать, если нужна доработка :)

Ответ 2



Ну ответ @PashaPash вполне исчерпывающий. Но, как я понял, вас не вставка иконки интересует, а получение исходной. Немного изучив вопрос. Вот, что получил. Само изображение можно получить штатными способами. Достаточно воспользоваться e.Data.GetData("DragImageBits"), где e - DragEventArgs. В данном случае вы получите само изображение в весьма примитивном формате. В начале идёт заголовок размером 6 int, где первые два - ширина и высота, вторые - точка захвата курсором X и Y, а последние - судя по всему либо MagicNumber, либо какая-то служебная инфа. После идёт само изображение в формате BGRA. Код, для получения изображения: 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); } В результате у вас BitmapSource - исходное изображение с иконкой и названием, Xpos и Ypos - координаты точки, где курсор держит изображение. Как это всё использовать видимо сами разберётесь.

Комментариев нет:

Отправить комментарий