diff --git a/src/Files.App.Controls/Sidebar/ISidebarViewModel.cs b/src/Files.App.Controls/Sidebar/ISidebarViewModel.cs index a3673e6d6105..41d8c037bceb 100644 --- a/src/Files.App.Controls/Sidebar/ISidebarViewModel.cs +++ b/src/Files.App.Controls/Sidebar/ISidebarViewModel.cs @@ -7,43 +7,8 @@ namespace Files.App.Controls { + public record ItemInvokedEventArgs(PointerUpdateKind PointerUpdateKind) { } public record ItemDroppedEventArgs(object DropTarget, DataPackageView DroppedItem, SidebarItemDropPosition dropPosition, DragEventArgs RawEvent) { } public record ItemDragOverEventArgs(object DropTarget, DataPackageView DroppedItem, SidebarItemDropPosition dropPosition, DragEventArgs RawEvent) { } public record ItemContextInvokedArgs(object? Item, Point Position) { } - - public interface ISidebarViewModel - { - /// - /// The source/list of items that will be rendered in the sidebar - /// - object SidebarItems { get; } - - /// - /// Gets invoked when the context was requested for an item in the sidebar. - /// Also applies when context was requested for the pane itsself. - /// - /// The sender of this event - /// The for this event. - void HandleItemContextInvokedAsync(object sender, ItemContextInvokedArgs args); - - /// - /// Gets invoked when an item drags over any item of the sidebar. - /// - /// The for this event. - /// A that represents the asynchronous operation. - Task HandleItemDragOverAsync(ItemDragOverEventArgs args); - - /// - /// Gets invoked when an item is dropped on any item of the sidebar. - /// - /// The for this event. - /// A that represents the asynchronous operation. - Task HandleItemDroppedAsync(ItemDroppedEventArgs args); - - /// - /// Gets invoked when an item is invoked (double clicked) on any item of the sidebar. - /// - /// The item that was invoked. - void HandleItemInvokedAsync(object item, PointerUpdateKind pointerUpdateKind); - } } diff --git a/src/Files.App.Controls/Sidebar/SidebarItem.cs b/src/Files.App.Controls/Sidebar/SidebarItem.cs index d1ac6b49e5a5..8959dc9a7043 100644 --- a/src/Files.App.Controls/Sidebar/SidebarItem.cs +++ b/src/Files.App.Controls/Sidebar/SidebarItem.cs @@ -404,12 +404,7 @@ private async void ItemBorder_DragOver(object sender, DragEventArgs e) VisualStateManager.GoToState(this, "DragInsertBelow", true); } - if (Owner is not null) - { - var deferral = e.GetDeferral(); - await Owner.RaiseItemDragOver(this, insertsAbove, e); - deferral.Complete(); - } + Owner?.RaiseItemDragOver(this, insertsAbove, e); } private void ItemBorder_ContextRequested(UIElement sender, Microsoft.UI.Xaml.Input.ContextRequestedEventArgs args) @@ -423,11 +418,10 @@ private void ItemBorder_DragLeave(object sender, DragEventArgs e) UpdatePointerState(); } - private async void ItemBorder_Drop(object sender, DragEventArgs e) + private void ItemBorder_Drop(object sender, DragEventArgs e) { UpdatePointerState(); - if (Owner is not null) - await Owner.RaiseItemDropped(this, DetermineDropTargetPosition(e), e); + Owner?.RaiseItemDropped(this, DetermineDropTargetPosition(e), e); } private SidebarItemDropPosition DetermineDropTargetPosition(DragEventArgs args) diff --git a/src/Files.App.Controls/Sidebar/SidebarItemAutomationPeer.cs b/src/Files.App.Controls/Sidebar/SidebarItemAutomationPeer.cs index 47721f6cc443..6d62f514afa7 100644 --- a/src/Files.App.Controls/Sidebar/SidebarItemAutomationPeer.cs +++ b/src/Files.App.Controls/Sidebar/SidebarItemAutomationPeer.cs @@ -9,6 +9,9 @@ namespace Files.App.Controls { + /// + /// Exposes types to Microsoft UI Automation. + /// public sealed partial class SidebarItemAutomationPeer : FrameworkElementAutomationPeer, IInvokeProvider, IExpandCollapseProvider, ISelectionItemProvider { public ExpandCollapseState ExpandCollapseState @@ -17,6 +20,7 @@ public ExpandCollapseState ExpandCollapseState { if (Owner.HasChildren) return Owner.IsExpanded ? ExpandCollapseState.Expanded : ExpandCollapseState.Collapsed; + return ExpandCollapseState.LeafNode; } } @@ -27,7 +31,7 @@ public ExpandCollapseState ExpandCollapseState public SidebarItemAutomationPeer(SidebarItem owner) : base(owner) { - this.Owner = owner; + Owner = owner; } protected override AutomationControlType GetAutomationControlTypeCore() @@ -49,28 +53,22 @@ protected override object GetPatternCore(PatternInterface patternInterface) else if (patternInterface == PatternInterface.ExpandCollapse) { if (Owner.CollapseEnabled) - { return this; - } } + return base.GetPatternCore(patternInterface); } public void Collapse() { if (Owner.CollapseEnabled) - { Owner.IsExpanded = false; - } } public void Expand() { - if (Owner.CollapseEnabled) - { Owner.IsExpanded = true; - } } public void Invoke() @@ -106,13 +104,11 @@ protected override int GetPositionInSetCore() private IList GetOwnerCollection() { if (Owner.FindAscendant() is SidebarItem parent && parent.Item?.Children is IList list) - { return list; - } - if (Owner?.Owner is not null && Owner.Owner.ViewModel.SidebarItems is IList items) - { + + if (Owner?.Owner is not null && Owner.Owner?.MenuItemsSource is IList items) return items; - } + return new List(); } } diff --git a/src/Files.App.Controls/Sidebar/SidebarView.Properties.cs b/src/Files.App.Controls/Sidebar/SidebarView.Properties.cs index 966484265344..9bf6bebed9ec 100644 --- a/src/Files.App.Controls/Sidebar/SidebarView.Properties.cs +++ b/src/Files.App.Controls/Sidebar/SidebarView.Properties.cs @@ -65,14 +65,6 @@ public double NegativeOpenPaneLength public static readonly DependencyProperty NegativeOpenPaneLengthProperty = DependencyProperty.Register(nameof(NegativeOpenPaneLength), typeof(double), typeof(SidebarView), new PropertyMetadata(null)); - public ISidebarViewModel ViewModel - { - get => (ISidebarViewModel)GetValue(ViewModelProperty); - set => SetValue(ViewModelProperty, value); - } - public static readonly DependencyProperty ViewModelProperty = - DependencyProperty.Register(nameof(ViewModel), typeof(ISidebarViewModel), typeof(SidebarView), new PropertyMetadata(null)); - public ISidebarItemModel SelectedItem { get => (ISidebarItemModel)GetValue(SelectedItemProperty); diff --git a/src/Files.App.Controls/Sidebar/SidebarView.xaml.cs b/src/Files.App.Controls/Sidebar/SidebarView.xaml.cs index 7675d46a2286..1ec03c66f9f4 100644 --- a/src/Files.App.Controls/Sidebar/SidebarView.xaml.cs +++ b/src/Files.App.Controls/Sidebar/SidebarView.xaml.cs @@ -15,8 +15,10 @@ public sealed partial class SidebarView : UserControl, INotifyPropertyChanged { private const double COMPACT_MAX_WIDTH = 200; - public event EventHandler? ItemInvoked; + public event EventHandler? ItemInvoked; public event EventHandler? ItemContextInvoked; + public event EventHandler? ItemDragOver; + public event EventHandler? ItemDropped; public event PropertyChangedEventHandler? PropertyChanged; internal SidebarItem? SelectedItemContainer = null; @@ -40,26 +42,24 @@ internal void RaiseItemInvoked(SidebarItem item, PointerUpdateKind pointerUpdate if (item.Item is null || item.IsGroupHeader) return; SelectedItem = item.Item; - ItemInvoked?.Invoke(item, item.Item); - ViewModel.HandleItemInvokedAsync(item.Item, pointerUpdateKind); + ItemInvoked?.Invoke(item, new(pointerUpdateKind)); } internal void RaiseContextRequested(SidebarItem item, Point e) { - ItemContextInvoked?.Invoke(item, new ItemContextInvokedArgs(item.Item, e)); - ViewModel.HandleItemContextInvokedAsync(item, new ItemContextInvokedArgs(item.Item, e)); + ItemContextInvoked?.Invoke(item, new(item.Item, e)); } - internal async Task RaiseItemDropped(SidebarItem sideBarItem, SidebarItemDropPosition dropPosition, DragEventArgs rawEvent) + internal void RaiseItemDropped(SidebarItem sideBarItem, SidebarItemDropPosition dropPosition, DragEventArgs rawEvent) { if (sideBarItem.Item is null) return; - await ViewModel.HandleItemDroppedAsync(new ItemDroppedEventArgs(sideBarItem.Item, rawEvent.DataView, dropPosition, rawEvent)); + ItemDropped?.Invoke(this, new(sideBarItem.Item, rawEvent.DataView, dropPosition, rawEvent)); } - internal async Task RaiseItemDragOver(SidebarItem sideBarItem, SidebarItemDropPosition dropPosition, DragEventArgs rawEvent) + internal void RaiseItemDragOver(SidebarItem sideBarItem, SidebarItemDropPosition dropPosition, DragEventArgs rawEvent) { if (sideBarItem.Item is null) return; - await ViewModel.HandleItemDragOverAsync(new ItemDragOverEventArgs(sideBarItem.Item, rawEvent.DataView, dropPosition, rawEvent)); + ItemDragOver?.Invoke(this, new(sideBarItem.Item, rawEvent.DataView, dropPosition, rawEvent)); } private void UpdateMinimalMode() @@ -230,8 +230,7 @@ private void SidebarResizer_ManipulationCompleted(object sender, ManipulationCom private void MenuItemHostScrollViewer_ContextRequested(UIElement sender, ContextRequestedEventArgs e) { - var newArgs = new ItemContextInvokedArgs(null, e.TryGetPosition(this, out var point) ? point : default); - ViewModel.HandleItemContextInvokedAsync(this, newArgs); + ItemContextInvoked?.Invoke(this, new(null, e.TryGetPosition(this, out var point) ? point : default)); e.Handled = true; } diff --git a/src/Files.App.Controls/Sidebar/SidebarViewAutomationPeer.cs b/src/Files.App.Controls/Sidebar/SidebarViewAutomationPeer.cs index 94c98558942e..6940756ea0da 100644 --- a/src/Files.App.Controls/Sidebar/SidebarViewAutomationPeer.cs +++ b/src/Files.App.Controls/Sidebar/SidebarViewAutomationPeer.cs @@ -6,6 +6,9 @@ namespace Files.App.Controls { + /// + /// Exposes types to Microsoft UI Automation. + /// public sealed partial class SidebarViewAutomationPeer : FrameworkElementAutomationPeer, ISelectionProvider { public bool CanSelectMultiple => false; @@ -20,20 +23,17 @@ public SidebarViewAutomationPeer(SidebarView owner) : base(owner) protected override object GetPatternCore(PatternInterface patternInterface) { - if (patternInterface == PatternInterface.Selection) - { + if (patternInterface is PatternInterface.Selection) return this; - } + return base.GetPatternCore(patternInterface); } public IRawElementProviderSimple[] GetSelection() { if (Owner.SelectedItemContainer != null) - return - [ - ProviderFromPeer(CreatePeerForElement(Owner.SelectedItemContainer)) - ]; + return [ProviderFromPeer(CreatePeerForElement(Owner.SelectedItemContainer))]; + return []; } } diff --git a/src/Files.App/ViewModels/UserControls/SidebarViewModel.cs b/src/Files.App/ViewModels/UserControls/SidebarViewModel.cs index 6c07f8ea1d20..c61337cd877f 100644 --- a/src/Files.App/ViewModels/UserControls/SidebarViewModel.cs +++ b/src/Files.App/ViewModels/UserControls/SidebarViewModel.cs @@ -19,7 +19,7 @@ namespace Files.App.ViewModels.UserControls { - public sealed partial class SidebarViewModel : ObservableObject, IDisposable, ISidebarViewModel + public sealed partial class SidebarViewModel : ObservableObject, IDisposable { private INetworkService NetworkService { get; } = Ioc.Default.GetRequiredService(); private IUserSettingsService UserSettingsService { get; } = Ioc.Default.GetRequiredService(); diff --git a/src/Files.App/Views/MainPage.xaml b/src/Files.App/Views/MainPage.xaml index d69d1aa9e223..3859b26271c2 100644 --- a/src/Files.App/Views/MainPage.xaml +++ b/src/Files.App/Views/MainPage.xaml @@ -180,11 +180,14 @@ HorizontalContentAlignment="Stretch" DisplayMode="{x:Bind SidebarAdaptiveViewModel.SidebarDisplayMode, Mode=TwoWay}" IsPaneOpen="{x:Bind ViewModel.IsSidebarPaneOpen, Mode=TwoWay}" + ItemContextInvoked="SidebarControl_ItemContextInvoked" + ItemDragOver="SidebarControl_ItemDragOver" + ItemDropped="SidebarControl_ItemDropped" + ItemInvoked="SidebarControl_ItemInvoked" Loaded="SidebarControl_Loaded" MenuItemsSource="{x:Bind SidebarAdaptiveViewModel.SidebarItems, Mode=OneWay}" OpenPaneLength="{x:Bind UserSettingsService.AppearanceSettingsService.SidebarWidth, Mode=TwoWay}" - SelectedItem="{x:Bind SidebarAdaptiveViewModel.SidebarSelectedItem, Mode=TwoWay}" - ViewModel="{x:Bind SidebarAdaptiveViewModel}"> + SelectedItem="{x:Bind SidebarAdaptiveViewModel.SidebarSelectedItem, Mode=TwoWay}"> diff --git a/src/Files.App/Views/MainPage.xaml.cs b/src/Files.App/Views/MainPage.xaml.cs index 0835decaca56..93ea9bbc5f49 100644 --- a/src/Files.App/Views/MainPage.xaml.cs +++ b/src/Files.App/Views/MainPage.xaml.cs @@ -13,6 +13,7 @@ using Microsoft.UI.Xaml.Navigation; using Windows.Foundation.Metadata; using Windows.Graphics; +using Windows.UI.Input; using WinUIEx; using GridSplitter = Files.App.Controls.GridSplitter; using VirtualKey = Windows.System.VirtualKey; @@ -465,5 +466,27 @@ private void Page_PointerReleased(object sender, PointerRoutedEventArgs e) // shortcuts from working properly, see https://github.com/microsoft/microsoft-ui-xaml/issues/6467 DispatcherQueue.TryEnqueue(() => ContentPageContext.ShellPage?.PaneHolder.FocusActivePane()); } + + private void SidebarControl_ItemContextInvoked(object sender, ItemContextInvokedArgs e) + { + SidebarAdaptiveViewModel.HandleItemContextInvokedAsync(sender, e); + } + + private async void SidebarControl_ItemDragOver(object sender, ItemDragOverEventArgs e) + { + var deferral = e.RawEvent.GetDeferral(); + await SidebarAdaptiveViewModel.HandleItemDragOverAsync(e); + deferral.Complete(); + } + + private async void SidebarControl_ItemDropped(object sender, ItemDroppedEventArgs e) + { + await SidebarAdaptiveViewModel.HandleItemDroppedAsync(e); + } + + private void SidebarControl_ItemInvoked(object sender, ItemInvokedEventArgs e) + { + SidebarAdaptiveViewModel.HandleItemInvokedAsync(((SidebarItem)sender).Item, e.PointerUpdateKind); + } } } \ No newline at end of file diff --git a/tests/Files.App.UITests/TestData/TestSidebarViewModel.cs b/tests/Files.App.UITests/TestData/TestSidebarViewModel.cs deleted file mode 100644 index be26cdae9136..000000000000 --- a/tests/Files.App.UITests/TestData/TestSidebarViewModel.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Files.App.Controls; -using Microsoft.UI.Input; -using System.Collections.ObjectModel; -using System.Threading.Tasks; - -namespace Files.App.UITests.TestData -{ - class TestSidebarViewModel : ISidebarViewModel - { - public object SidebarItems { get; set; } = new ObservableCollection(); - - public void HandleItemContextInvokedAsync(object sender, ItemContextInvokedArgs args) - { - } - - public Task HandleItemDragOverAsync(ItemDragOverEventArgs args) - { - return Task.CompletedTask; - } - - public Task HandleItemDroppedAsync(ItemDroppedEventArgs args) - { - return Task.CompletedTask; - } - - public void HandleItemInvokedAsync(object item, PointerUpdateKind pointerUpdateKind) - { - } - } -} diff --git a/tests/Files.App.UITests/Views/SidebarViewPage.xaml.cs b/tests/Files.App.UITests/Views/SidebarViewPage.xaml.cs index 3c1050de8615..ee4dbf164c18 100644 --- a/tests/Files.App.UITests/Views/SidebarViewPage.xaml.cs +++ b/tests/Files.App.UITests/Views/SidebarViewPage.xaml.cs @@ -15,8 +15,6 @@ public SidebarViewPage() sidebarModels.Add(new TestSidebarModel { Text = "Test 1" }); sidebarModels.Add(new TestSidebarModel { Text = "Test 2" }); sidebarModels.Add(new TestSidebarModel { Text = "Test 3" }); - - Sidebar.ViewModel = new TestSidebarViewModel(); } } }