mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 18:57:19 +02:00
CmdPal: Add drag & drop support (#44165)
## Summary of the Pull Request This PR adds basic drag-and-drop support for items in list and grid views. It introduces two new properties on `ListItem`, backed by `IExtendedAttributesProvider`: `DataPackage` and `DataPackageView`. These properties are mutually exclusive. `DataPackage` serves as a convenience property allowing the item to retain the underlying object without risk of losing it. Across the extension boundary, only the immutable `DataPackageView` snapshot is transferred. When `DataPackage` is set, `DataPackageView` is derived from it. This PR includes initial concrete drag-and-drop implementations for: - File Indexer - Clipboard History **Todo / Missing pieces** - [x] Extend `DataPackage` support to top-level command items, enabling scenarios such as index fallback ~ - [x] Provide automatic drag-and-drop for unconfigured list items (e.g., copying title and subtitle as text) - [x] Keep CmdPal open - [ ] ~Clipboard commands (since we have the DataPackage...)~ - [ ] ~Improve logging~ ## Pictures? Moving ones! https://github.com/user-attachments/assets/13eb9a71-e760-43ea-8c2d-cd41cf377905 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] Closes: #38289 <!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
This commit is contained in:
@@ -439,9 +439,12 @@
|
||||
<ListView
|
||||
x:Name="ItemsList"
|
||||
Padding="0,2,0,0"
|
||||
CanDragItems="True"
|
||||
ContextCanceled="Items_OnContextCanceled"
|
||||
ContextRequested="Items_OnContextRequested"
|
||||
DoubleTapped="Items_DoubleTapped"
|
||||
DragItemsCompleted="Items_DragItemsCompleted"
|
||||
DragItemsStarting="Items_DragItemsStarting"
|
||||
IsDoubleTapEnabled="True"
|
||||
IsItemClickEnabled="True"
|
||||
ItemClick="Items_ItemClick"
|
||||
@@ -458,9 +461,12 @@
|
||||
<GridView
|
||||
x:Name="ItemsGrid"
|
||||
Padding="16,0"
|
||||
CanDragItems="True"
|
||||
ContextCanceled="Items_OnContextCanceled"
|
||||
ContextRequested="Items_OnContextRequested"
|
||||
DoubleTapped="Items_DoubleTapped"
|
||||
DragItemsCompleted="Items_DragItemsCompleted"
|
||||
DragItemsStarting="Items_DragItemsStarting"
|
||||
IsDoubleTapEnabled="True"
|
||||
IsItemClickEnabled="True"
|
||||
ItemClick="Items_ItemClick"
|
||||
|
||||
@@ -18,6 +18,7 @@ using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.Foundation;
|
||||
using Windows.System;
|
||||
|
||||
@@ -891,6 +892,89 @@ public sealed partial class ListPage : Page,
|
||||
ItemView.SelectedIndex = newIndex;
|
||||
}
|
||||
|
||||
private void Items_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Items.FirstOrDefault() is not ListItemViewModel item || item.DataPackage is null)
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// copy properties
|
||||
foreach (var (key, value) in item.DataPackage.Properties)
|
||||
{
|
||||
try
|
||||
{
|
||||
e.Data.Properties[key] = value;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// noop - skip any properties that fail
|
||||
}
|
||||
}
|
||||
|
||||
// setup e.Data formats as deferred renderers to read from the item's DataPackage
|
||||
foreach (var format in item.DataPackage.AvailableFormats)
|
||||
{
|
||||
try
|
||||
{
|
||||
e.Data.SetDataProvider(format, request => DelayRenderer(request, item, format));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// noop - skip any formats that fail
|
||||
}
|
||||
}
|
||||
|
||||
WeakReferenceMessenger.Default.Send(new DragStartedMessage());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(new DragCompletedMessage());
|
||||
Logger.LogError("Failed to start dragging an item", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DelayRenderer(DataProviderRequest request, ListItemViewModel item, string format)
|
||||
{
|
||||
var deferral = request.GetDeferral();
|
||||
try
|
||||
{
|
||||
item.DataPackage?.GetDataAsync(format)
|
||||
.AsTask()
|
||||
.ContinueWith(dataTask =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (dataTask.IsCompletedSuccessfully)
|
||||
{
|
||||
request.SetData(dataTask.Result);
|
||||
}
|
||||
else if (dataTask.IsFaulted && dataTask.Exception is not null)
|
||||
{
|
||||
Logger.LogError($"Failed to get data for format '{format}' during drag-and-drop", dataTask.Exception);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
deferral.Complete();
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"Failed to set data for format '{format}' during drag-and-drop", ex);
|
||||
deferral.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
private void Items_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(new DragCompletedMessage());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Code stealed from <see cref="Controls.ContextMenu.NavigateDown"/>
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user