Repository navigation
Description
Current behavior 🐛
On Desktop (Windows), when something is dragged into an Uno window from another app, the source app's own drag image doesn't show over the window. For example, Explorer's file thumbnail, or a browser's picture of a dragged image, disappears as soon as the pointer enters the window. The Win32 drop target doesn't forward its calls to the shell's drag-image manager (IDropTargetHelper), which is what draws a source's drag image over a drop target's window.
Instead, Uno builds a preview of its own, in CreateDragUIForExternalDrag (Win32DragDropExtension.DragUI.cs):
- if the drag offers a bitmap (CF_DIB), it reads it with a second
IDataObject::GetDataand passes it toBitmapImage.SetSource; - otherwise, it loads the first image file of the dropped file list from disk;
- otherwise, it extracts the first file's icon.
The bitmap preview never shows: it's a raw DIB, without the 14-byte BMP file header, and the image decoders only recognize a BMP by its BM signature. Since a BitmapImage is always returned, a drag that offers both a bitmap and files never falls back to the file icon either. The preview also costs a second copy of the bitmap at every DragEnter, and a file read or icon extraction on the UI thread.
On master, none of these previews show at the moment: since #25124, the drag visual's image never shows (#25869). On Uno 6.8, the file thumbnail and icon do.
Expected behavior 🎯
As in WinUI: the source's own drag image follows the pointer over the window, with the glyph and caption of the drop target's accepted operation. Content that the drop target sets with DragUIOverride.SetContentFromBitmapImage replaces it, and DragUIOverride.IsContentVisible = false hides it.
WinUI doesn't build a drag visual from the dragged data:
- WinUI gets its drop target from
Microsoft.UI.Input.DragDrop.DragDropManager.GetForIsland(XamlIslandRoot.cpp), and that layer draws the drag visual. DropOperationTarget::EnterAsyncandOverAsynconly raise the XAML drag events with theDragUIOverridethey receive.RaiseDragDropEventAsyncOperation::OnCustomVisualSetUponly changes the visual when the app set content: "Drop target needs to set DragVisual on the eventargs in order to set the custom visual, otherwise, dragged visual will not be changed." Otherwise, it only clears an earlier override, once the drag has left the element that set it.- Nothing in the XAML layer reads the dragged data,
CF_DIB, files or the shell's drag image to make a preview.
The docs describe the same model. DragUIOverride lets the drop target set, show or hide the content, caption and glyph of the drag visual. IDropTargetHelper "exposes methods that allow drop targets to display a drag image while the image is over the target window".
Uno's other hosts don't build a preview either: the macOS, X11 and WebAssembly hosts pass no DragUI for an external drag (MacOSDragDropExtension.HandleDragEntered, X11DragDropExtension, BrowserDragDropExtension). On macOS, on X11 and in the browser (WebAssembly), the source's own drag image shows.
How to reproduce it (as minimally and precisely as possible) 🔬
- Put an element with
AllowDrop="True"in a window, and sete.AcceptedOperation = DataPackageOperation.Copyin itsDragOverhandler. - Run the app on Desktop (Windows).
- Drag a file from Explorer, or an image from a browser, over the element.
- The source's drag image disappears over the window. On Uno 6.8, Uno shows its own small thumbnail of an image file instead, and the icon of other files. On
master, nothing shows at all, since the drag visual's image doesn't show there at the moment (In-app drags no longer show the dragged element: the drag visual is never loaded #25869). For a drag that offers a bitmap, nothing shows on either.
The DragDrop_ExternalDragVisual sample in #25874 shows each case. The runtime test Given_Win32ExternalDrag.When_Bitmap_Dragged_Over_Then_No_Preview_Is_Generated in the same PR shows that Uno makes its own content for a CF_DIB drag, which WinUI never does. It drives the window's drop target in-process with a shell data object, and fails on master at 1f2fc30, and on our 6.8-based branch.
Workaround 🛠️
An app can set its own preview with DragUIOverride.SetContentFromBitmapImage in DragOver (on master, that also needs #25870, as the drag visual's content doesn't show there at the moment). The source's drag image can't be shown from app code.
Affected platforms 📱💻🖥️
Desktop (Windows)
Uno.Sdk version (and other relevant versions) 📦
master at 1f2fc30, and Uno 6.8 (servicing/6.8 at 6951c2c), which has the same code. What shows instead of the source's image differs: Uno's own thumbnail or icon on Uno 6.8, nothing on master (#25869).
IDE version 🧑💻
Not IDE-related.
Anything else we need to know? 💬
The preview was added by #21759. CLSID.DragDropHelper is already declared in Uno.UI.Runtime.Win32.Support, but nothing uses it.
Activity