From 263704a7724ad7cfb1570107a96ea149fb2e78a3 Mon Sep 17 00:00:00 2001 From: "dan_clark@outlook.com" Date: Wed, 23 Mar 2022 21:19:23 +0000 Subject: [PATCH] Add drag/drop handling --- .../IAsyncMessageHandler.cs | 9 ++- .../IMessageHandler.cs | 8 ++- ...ggregatorInvoker.cs => IMessageInvoker.cs} | 2 +- .../IObservableExtensions.cs | 2 +- .../IServiceCollectionExtensions.cs | 45 +++++++++++- TheXamlGuy.TaskbarGroup.Core/Mediator.cs | 1 + ...AggregatorInvoker.cs => MessageInvoker.cs} | 2 +- TheXamlGuy.TaskbarGroup.Core/Messenger.cs | 4 +- .../Drop.cs | 9 +++ .../DropTarget.cs | 68 ++++++++----------- .../IDropHandler.cs | 10 +++ .../IServiceCollectionExtensions.cs | 3 +- ...lGuy.TaskbarGroup.Flyout.Foundation.csproj | 7 +- .../Controls/TaskbarButtonFlyout.cs | 4 -- .../TheXamlGuy.TaskbarGroup.Flyout.csproj | 4 ++ .../Views/TaskbarButtonGroupDropHandler.cs | 49 +++++++++++++ .../Views/TaskbarButtonGroupItemViewModel.cs | 1 + .../Views/TaskbarButtonGroupView.xaml | 8 ++- .../Views/TaskbarButtonGroupViewModel.cs | 8 ++- .../Views/TaskbarButtonView.xaml | 2 +- .../Views/TaskbarButtonViewModel.cs | 3 +- TheXamlGuy.TaskbarGroup/App.xaml.cs | 3 +- 22 files changed, 189 insertions(+), 63 deletions(-) rename TheXamlGuy.TaskbarGroup.Core/{IEventAggregatorInvoker.cs => IMessageInvoker.cs} (79%) rename TheXamlGuy.TaskbarGroup.Core/{EventAggregatorInvoker.cs => MessageInvoker.cs} (83%) create mode 100644 TheXamlGuy.TaskbarGroup.Flyout.Foundation/Drop.cs create mode 100644 TheXamlGuy.TaskbarGroup.Flyout.Foundation/IDropHandler.cs create mode 100644 TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonGroupDropHandler.cs diff --git a/TheXamlGuy.TaskbarGroup.Core/IAsyncMessageHandler.cs b/TheXamlGuy.TaskbarGroup.Core/IAsyncMessageHandler.cs index f291eb7..81e66ac 100644 --- a/TheXamlGuy.TaskbarGroup.Core/IAsyncMessageHandler.cs +++ b/TheXamlGuy.TaskbarGroup.Core/IAsyncMessageHandler.cs @@ -1,11 +1,16 @@ namespace TheXamlGuy.TaskbarGroup.Core { - public interface IAsyncMessageHandler + public interface IAsyncMessageHandler + { + + } + + public interface IAsyncMessageHandler : IAsyncMessageHandler { Task Handle(TMessage message, CancellationToken canellationToken = default); } - public interface IAsyncMessageHandler + public interface IAsyncMessageHandler : IAsyncMessageHandler { Task Handle(TMessage message, CancellationToken cancellationToken = default); } diff --git a/TheXamlGuy.TaskbarGroup.Core/IMessageHandler.cs b/TheXamlGuy.TaskbarGroup.Core/IMessageHandler.cs index eaf99ec..67d984a 100644 --- a/TheXamlGuy.TaskbarGroup.Core/IMessageHandler.cs +++ b/TheXamlGuy.TaskbarGroup.Core/IMessageHandler.cs @@ -1,11 +1,15 @@ namespace TheXamlGuy.TaskbarGroup.Core { - public interface IMessageHandler + public interface IMessageHandler + { + + } + public interface IMessageHandler : IMessageHandler { void Handle(TMessage message); } - public interface IMessageHandler + public interface IMessageHandler : IMessageHandler { TReturn Handle(TMessage message); } diff --git a/TheXamlGuy.TaskbarGroup.Core/IEventAggregatorInvoker.cs b/TheXamlGuy.TaskbarGroup.Core/IMessageInvoker.cs similarity index 79% rename from TheXamlGuy.TaskbarGroup.Core/IEventAggregatorInvoker.cs rename to TheXamlGuy.TaskbarGroup.Core/IMessageInvoker.cs index c9349cd..42c823d 100644 --- a/TheXamlGuy.TaskbarGroup.Core/IEventAggregatorInvoker.cs +++ b/TheXamlGuy.TaskbarGroup.Core/IMessageInvoker.cs @@ -2,7 +2,7 @@ namespace TheXamlGuy.TaskbarGroup.Core { - public interface IEventAggregatorInvoker + public interface IMessageInvoker { void Invoke(object target, TMessage message, MethodInfo methodInfo); } diff --git a/TheXamlGuy.TaskbarGroup.Core/IObservableExtensions.cs b/TheXamlGuy.TaskbarGroup.Core/IObservableExtensions.cs index e084c5a..9a3c007 100644 --- a/TheXamlGuy.TaskbarGroup.Core/IObservableExtensions.cs +++ b/TheXamlGuy.TaskbarGroup.Core/IObservableExtensions.cs @@ -6,7 +6,7 @@ namespace TheXamlGuy.TaskbarGroup.Core public static class IObservableExtensions { - public static IDisposable WeakSubscribe(this IObservable observable, IEventAggregatorInvoker invoker, Action actionDelegate) + public static IDisposable WeakSubscribe(this IObservable observable, IMessageInvoker invoker, Action actionDelegate) { var methodInfo = actionDelegate.Method; var weakReference = new WeakReference(actionDelegate.Target); diff --git a/TheXamlGuy.TaskbarGroup.Core/IServiceCollectionExtensions.cs b/TheXamlGuy.TaskbarGroup.Core/IServiceCollectionExtensions.cs index 7fbce88..e8fcaf4 100644 --- a/TheXamlGuy.TaskbarGroup.Core/IServiceCollectionExtensions.cs +++ b/TheXamlGuy.TaskbarGroup.Core/IServiceCollectionExtensions.cs @@ -4,12 +4,55 @@ namespace TheXamlGuy.TaskbarGroup.Core { public static class IServiceCollectionExtensions { + public static IServiceCollection AddAsyncHandler(this IServiceCollection serviceCollection) + where TAsyncMessageHandle : IAsyncMessageHandler + { + if (typeof(TAsyncMessageHandle).GetInterfaces().FirstOrDefault(x => + x.GetGenericTypeDefinition() == typeof(IAsyncMessageHandler<>) + || x.GetGenericTypeDefinition() == typeof(IAsyncMessageHandler<>)) is { } messageHandler) + { + var messageArguments = messageHandler.GetGenericArguments(); + if (messageArguments is { Length: 1 }) + { + serviceCollection.AddTransient(typeof(IAsyncMessageHandler<>).MakeGenericType(messageArguments[0]), typeof(TAsyncMessageHandle)); + } + else + { + serviceCollection.AddTransient(typeof(IAsyncMessageHandler<,>).MakeGenericType(messageArguments[0], messageArguments[1]), typeof(TAsyncMessageHandle)); + } + } + + return serviceCollection; + } + + public static IServiceCollection AddHandler(this IServiceCollection serviceCollection) + where TMessageHandle : IMessageHandler + { + if (typeof(TMessageHandle).GetInterfaces().FirstOrDefault(x => + x.GetGenericTypeDefinition() == typeof(IMessageHandler<>) + || x.GetGenericTypeDefinition() == typeof(IMessageHandler<,>)) is { } messageHandler) + { + var messageArguments = messageHandler.GetGenericArguments(); + + if (messageArguments is { Length: 1 }) + { + serviceCollection.AddTransient(typeof(IMessageHandler<>).MakeGenericType(messageArguments[0]), typeof(TMessageHandle)); + } + else + { + serviceCollection.AddTransient(typeof(IMessageHandler<,>).MakeGenericType(messageArguments[0], messageArguments[1]), typeof(TMessageHandle)); + } + } + + return serviceCollection; + } + public static IServiceCollection AddRequiredCore(this IServiceCollection serviceCollection) { return serviceCollection .AddSingleton() .AddSingleton(provider => new ServiceFactory(provider.GetService, (type, parameter) => ActivatorUtilities.CreateInstance(provider, type, parameter))) - .AddSingleton() + .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() diff --git a/TheXamlGuy.TaskbarGroup.Core/Mediator.cs b/TheXamlGuy.TaskbarGroup.Core/Mediator.cs index a1a9c00..ac9a602 100644 --- a/TheXamlGuy.TaskbarGroup.Core/Mediator.cs +++ b/TheXamlGuy.TaskbarGroup.Core/Mediator.cs @@ -40,6 +40,7 @@ { return HandleAsync(new TRequest(), parameters); } + public Task HandleAsync(object request, CancellationToken cancellationToken, params object[] parameters) { return GetHandler(typeof(IAsyncMessageHandler<>).MakeGenericType(request.GetType()), parameters) diff --git a/TheXamlGuy.TaskbarGroup.Core/EventAggregatorInvoker.cs b/TheXamlGuy.TaskbarGroup.Core/MessageInvoker.cs similarity index 83% rename from TheXamlGuy.TaskbarGroup.Core/EventAggregatorInvoker.cs rename to TheXamlGuy.TaskbarGroup.Core/MessageInvoker.cs index 40cc3f4..d933695 100644 --- a/TheXamlGuy.TaskbarGroup.Core/EventAggregatorInvoker.cs +++ b/TheXamlGuy.TaskbarGroup.Core/MessageInvoker.cs @@ -2,7 +2,7 @@ namespace TheXamlGuy.TaskbarGroup.Core { - public class EventAggregatorInvoker : IEventAggregatorInvoker + public class MessageInvoker : IMessageInvoker { public void Invoke(object target, TMessage message, MethodInfo methodInfo) { diff --git a/TheXamlGuy.TaskbarGroup.Core/Messenger.cs b/TheXamlGuy.TaskbarGroup.Core/Messenger.cs index 9e1a684..31ed461 100644 --- a/TheXamlGuy.TaskbarGroup.Core/Messenger.cs +++ b/TheXamlGuy.TaskbarGroup.Core/Messenger.cs @@ -7,12 +7,12 @@ namespace TheXamlGuy.TaskbarGroup.Core { public class Messenger : IMessenger { - public IEventAggregatorInvoker invoker; + public IMessageInvoker invoker; private readonly ConcurrentDictionary subjects = new(); private IScheduler dispatcher; - public Messenger(IEventAggregatorInvoker invoker) + public Messenger(IMessageInvoker invoker) { var synchronizationContext = SynchronizationContext.Current; if (synchronizationContext is null) throw new NullReferenceException(nameof(synchronizationContext)); diff --git a/TheXamlGuy.TaskbarGroup.Flyout.Foundation/Drop.cs b/TheXamlGuy.TaskbarGroup.Flyout.Foundation/Drop.cs new file mode 100644 index 0000000..e9e430f --- /dev/null +++ b/TheXamlGuy.TaskbarGroup.Flyout.Foundation/Drop.cs @@ -0,0 +1,9 @@ +using Windows.UI.Xaml; + +namespace TheXamlGuy.TaskbarGroup.Flyout.Foundation +{ + public record class Drop(DragEventArgs DropEventArgs) where TTarget : UIElement + { + public TTarget Target { get; } + } +} diff --git a/TheXamlGuy.TaskbarGroup.Flyout.Foundation/DropTarget.cs b/TheXamlGuy.TaskbarGroup.Flyout.Foundation/DropTarget.cs index 33a6c74..8d40a37 100644 --- a/TheXamlGuy.TaskbarGroup.Flyout.Foundation/DropTarget.cs +++ b/TheXamlGuy.TaskbarGroup.Flyout.Foundation/DropTarget.cs @@ -1,55 +1,43 @@ -using System; -using System.Collections.Generic; +using Microsoft.Xaml.Interactivity; +using System; +using TheXamlGuy.TaskbarGroup.Core; using Windows.ApplicationModel.DataTransfer; -using Windows.Storage; using Windows.UI.Xaml; namespace TheXamlGuy.TaskbarGroup.Flyout.Foundation { - public class DropTarget + public class DropTarget : Behavior { - public void Initialize(UIElement target) + public static readonly DependencyProperty MediatorProperty = + DependencyProperty.Register(nameof(Mediator), + typeof(IMediator), typeof(DropTarget), + new PropertyMetadata(null)); + + public IMediator Mediator { - target.DragOver += OnDragOver; - target.Drop += OnDrop; + get => (IMediator)GetValue(MediatorProperty); + set => SetValue(MediatorProperty, value); } - private async void OnDrop(object sender, DragEventArgs args) + protected override void OnAttached() { - if (args.DataView.Contains(StandardDataFormats.StorageItems)) + AssociatedObject.DragOver -= OnDragOver; + AssociatedObject.Drop -= OnDrop; + + AssociatedObject.DragOver += OnDragOver; + AssociatedObject.Drop += OnDrop; + + base.OnAttached(); + } + + private void OnDrop(object sender, DragEventArgs args) + { + if (Mediator is not null) { - var items = await args.DataView.GetStorageItemsAsync(); - if (items.Count > 0) - { - foreach (var storageItem in items) - { - if (storageItem is StorageFile storageFile) - { - if (storageFile.Path is { Length: > 0 }) - { + var dropMessageType = typeof(Drop<>).MakeGenericType(sender.GetType()); + var dropMessage = Activator.CreateInstance(dropMessageType, args); - } - else - { - var properties = await storageFile.Properties.RetrievePropertiesAsync(new List - { - "System.AppUserModel.ID" - }); - - var appUserModelId = properties["System.AppUserModel.ID"]; - if (appUserModelId is not null) - { - - } - } - } - - if (storageItem is StorageFolder storageFolder) - { - - } - } - } + Mediator.HandleAsync(dropMessage); } } diff --git a/TheXamlGuy.TaskbarGroup.Flyout.Foundation/IDropHandler.cs b/TheXamlGuy.TaskbarGroup.Flyout.Foundation/IDropHandler.cs new file mode 100644 index 0000000..58cb6cc --- /dev/null +++ b/TheXamlGuy.TaskbarGroup.Flyout.Foundation/IDropHandler.cs @@ -0,0 +1,10 @@ +using TheXamlGuy.TaskbarGroup.Core; +using Windows.UI.Xaml; + +namespace TheXamlGuy.TaskbarGroup.Flyout.Foundation +{ + public interface IDropHandler : IAsyncMessageHandler> where TTarget : UIElement + { + + } +} diff --git a/TheXamlGuy.TaskbarGroup.Flyout.Foundation/IServiceCollectionExtensions.cs b/TheXamlGuy.TaskbarGroup.Flyout.Foundation/IServiceCollectionExtensions.cs index 7f6238c..30bbcd6 100644 --- a/TheXamlGuy.TaskbarGroup.Flyout.Foundation/IServiceCollectionExtensions.cs +++ b/TheXamlGuy.TaskbarGroup.Flyout.Foundation/IServiceCollectionExtensions.cs @@ -12,7 +12,8 @@ namespace TheXamlGuy.TaskbarGroup.Flyout.Foundation return serviceCollection .AddSingleton() .AddSingleton(new DataTemplateCollection(new Dictionary())) - .AddSingleton(); + .AddSingleton() + .AddSingleton(); } } } diff --git a/TheXamlGuy.TaskbarGroup.Flyout.Foundation/TheXamlGuy.TaskbarGroup.Flyout.Foundation.csproj b/TheXamlGuy.TaskbarGroup.Flyout.Foundation/TheXamlGuy.TaskbarGroup.Flyout.Foundation.csproj index c032125..b7da097 100644 --- a/TheXamlGuy.TaskbarGroup.Flyout.Foundation/TheXamlGuy.TaskbarGroup.Flyout.Foundation.csproj +++ b/TheXamlGuy.TaskbarGroup.Flyout.Foundation/TheXamlGuy.TaskbarGroup.Flyout.Foundation.csproj @@ -122,9 +122,11 @@ PackageReference - + + + @@ -142,6 +144,9 @@ 2.8.0-prerelease.220118001 + + 2.0.1 + diff --git a/TheXamlGuy.TaskbarGroup.Flyout/Controls/TaskbarButtonFlyout.cs b/TheXamlGuy.TaskbarGroup.Flyout/Controls/TaskbarButtonFlyout.cs index 93de67e..e684c78 100644 --- a/TheXamlGuy.TaskbarGroup.Flyout/Controls/TaskbarButtonFlyout.cs +++ b/TheXamlGuy.TaskbarGroup.Flyout/Controls/TaskbarButtonFlyout.cs @@ -24,10 +24,6 @@ namespace TheXamlGuy.TaskbarGroup.Flyout.Controls TemplateSettings = new TaskbarButtonFlyoutTemplateSettings(); } - public event EventHandler Closed; - - public event EventHandler Opened; - public TaskbarButtonFlyoutTemplateSettings TemplateSettings { get => (TaskbarButtonFlyoutTemplateSettings)GetValue(TemplateSettingsProperty); diff --git a/TheXamlGuy.TaskbarGroup.Flyout/TheXamlGuy.TaskbarGroup.Flyout.csproj b/TheXamlGuy.TaskbarGroup.Flyout/TheXamlGuy.TaskbarGroup.Flyout.csproj index 5f559af..7e8d2b5 100644 --- a/TheXamlGuy.TaskbarGroup.Flyout/TheXamlGuy.TaskbarGroup.Flyout.csproj +++ b/TheXamlGuy.TaskbarGroup.Flyout/TheXamlGuy.TaskbarGroup.Flyout.csproj @@ -78,6 +78,7 @@ + TaskbarButtonGroupView.xaml @@ -119,6 +120,9 @@ 2.8.0-prerelease.220118001 + + 2.0.1 + diff --git a/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonGroupDropHandler.cs b/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonGroupDropHandler.cs new file mode 100644 index 0000000..9e42bce --- /dev/null +++ b/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonGroupDropHandler.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using TheXamlGuy.TaskbarGroup.Flyout.Foundation; +using Windows.ApplicationModel.DataTransfer; +using Windows.Storage; + +namespace TheXamlGuy.TaskbarGroup.Flyout +{ + public class TaskbarButtonGroupDropHandler : IDropHandler + { + public async Task Handle(Drop message, CancellationToken canellationToken = default) + { + if (message.DropEventArgs.DataView.Contains(StandardDataFormats.StorageItems)) + { + var items = await message.DropEventArgs.DataView.GetStorageItemsAsync(); + foreach (var storageItem in items) + { + if (storageItem is StorageFile storageFile) + { + if (storageFile.Path is { Length: > 0 }) + { + + } + else + { + var properties = await storageFile.Properties.RetrievePropertiesAsync(new List + { + "System.AppUserModel.ID" + }); + + var appUserModelId = properties["System.AppUserModel.ID"]; + if (appUserModelId is not null) + { + + } + } + } + + if (storageItem is StorageFolder storageFolder) + { + + } + } + } + } + } +} diff --git a/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonGroupItemViewModel.cs b/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonGroupItemViewModel.cs index 3ebda79..bbaa5dc 100644 --- a/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonGroupItemViewModel.cs +++ b/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonGroupItemViewModel.cs @@ -8,6 +8,7 @@ namespace TheXamlGuy.TaskbarGroup.Flyout IServiceFactory serviceFactory, IDisposer disposer) : base(messenger, serviceFactory, disposer) { + } public string Name { get; set; } diff --git a/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonGroupView.xaml b/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonGroupView.xaml index 5c85f21..dfb354a 100644 --- a/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonGroupView.xaml +++ b/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonGroupView.xaml @@ -2,8 +2,13 @@ x:Class="TheXamlGuy.TaskbarGroup.Flyout.TaskbarButtonGroupView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:foundation="using:TheXamlGuy.TaskbarGroup.Flyout.Foundation" + xmlns:interactivity="using:Microsoft.Xaml.Interactivity" AllowDrop="True"> - + + + + - \ No newline at end of file diff --git a/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonGroupViewModel.cs b/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonGroupViewModel.cs index a2f689d..caf2adf 100644 --- a/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonGroupViewModel.cs +++ b/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonGroupViewModel.cs @@ -5,15 +5,19 @@ namespace TheXamlGuy.TaskbarGroup.Flyout { public partial class TaskbarButtonGroupViewModel : ObservableCollectionViewModel { + [ObservableProperty] + private string name = "hello"; + public TaskbarButtonGroupViewModel(IMessenger messenger, IServiceFactory serviceFactory, + IMediator mediator, IDisposer disposer) : base(messenger, serviceFactory, disposer) { Register(OnFileDropped); + Mediator = mediator; } - [ObservableProperty] - private string name = "hello"; + public IMediator Mediator { get; } private void OnFileDropped(FileDropped args) { diff --git a/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonView.xaml b/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonView.xaml index 5ef39b2..c16292d 100644 --- a/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonView.xaml +++ b/TheXamlGuy.TaskbarGroup.Flyout/Views/TaskbarButtonView.xaml @@ -2,7 +2,7 @@ x:Class="TheXamlGuy.TaskbarGroup.Flyout.TaskbarButtonView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> - + , TaskbarButtonFlyoutActivationHandler>() + .AddHandler() .AddSingleton() .AddTransient() .AddTransient() .AddTransient() + .AddAsyncHandler() .AddTransient(); } }