From aaf0b7d0697b91b1cb9151551c9c7514e28927e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Thu, 9 Apr 2026 01:01:28 +0200 Subject: [PATCH] Better creation of context menu items for calendar events. --- .../Calendar/CalendarItemCommandBarFlyout.cs | 64 +++++++------------ .../Calendar/CalendarItemControl.xaml | 10 +-- .../Calendar/CalendarItemControl.xaml.cs | 41 ++++++++++-- .../Views/Calendar/CalendarPage.xaml.cs | 43 ++++++++++--- 4 files changed, 98 insertions(+), 60 deletions(-) diff --git a/Wino.Mail.WinUI/Controls/Calendar/CalendarItemCommandBarFlyout.cs b/Wino.Mail.WinUI/Controls/Calendar/CalendarItemCommandBarFlyout.cs index 91bd2a44..bf605773 100644 --- a/Wino.Mail.WinUI/Controls/Calendar/CalendarItemCommandBarFlyout.cs +++ b/Wino.Mail.WinUI/Controls/Calendar/CalendarItemCommandBarFlyout.cs @@ -1,56 +1,30 @@ -using System.Collections.Generic; +using System.Collections.Generic; +using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; -using Wino.Calendar.ViewModels.Messages; using Wino.Calendar.ViewModels.Data; +using Wino.Calendar.ViewModels.Messages; using Wino.Core.Domain; using Wino.Core.Domain.Enums; -using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.Calendar; -using Wino.Mail.WinUI; using Wino.Mail.WinUI.Controls; namespace Wino.Calendar.Controls; public partial class CalendarItemCommandBarFlyout : CommandBarFlyout { - private readonly ICalendarContextMenuItemService _contextMenuItemService; - - public static readonly DependencyProperty ItemProperty = DependencyProperty.Register(nameof(Item), typeof(CalendarItemViewModel), typeof(CalendarItemCommandBarFlyout), new PropertyMetadata(null, new PropertyChangedCallback(OnItemChanged))); - - public CalendarItemViewModel Item - { - get { return (CalendarItemViewModel)GetValue(ItemProperty); } - set { SetValue(ItemProperty, value); } - } + private readonly RelayCommand _executeActionCommand; public CalendarItemCommandBarFlyout() { - _contextMenuItemService = WinoApplication.Current.Services.GetRequiredService(); - Opening += FlyoutOpening; + _executeActionCommand = new RelayCommand(ExecuteAction); } - private static void OnItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + public CalendarItemViewModel? Item { get; set; } + + public void SetMenuItems(IReadOnlyList menuItems) { - if (d is CalendarItemCommandBarFlyout flyout) - { - flyout.UpdateMenuItems(); - } - } - - private void FlyoutOpening(object sender, object e) => UpdateMenuItems(); - - private void UpdateMenuItems() - { - PrimaryCommands.Clear(); - SecondaryCommands.Clear(); - - if (Item?.CalendarItem == null) - return; - - var menuItems = _contextMenuItemService.GetContextMenuItems(Item.CalendarItem); + ClearMenuItems(); foreach (var menuItem in menuItems) { @@ -63,12 +37,20 @@ public partial class CalendarItemCommandBarFlyout : CommandBarFlyout } } + public void ClearMenuItems() + { + PrimaryCommands.Clear(); + SecondaryCommands.Clear(); + } + private AppBarButton BuildAppBarButton(CalendarContextMenuItem menuItem) { var button = new AppBarButton { Label = GetActionLabel(menuItem.Action), IsEnabled = menuItem.IsEnabled, + Command = _executeActionCommand, + CommandParameter = menuItem.Action, Icon = new WinoFontIcon { Icon = GetActionIcon(menuItem.Action), @@ -82,10 +64,6 @@ public partial class CalendarItemCommandBarFlyout : CommandBarFlyout PopulateMenuFlyoutItems(flyout.Items, menuItem.Children); button.Flyout = flyout; } - else - { - button.Click += (_, _) => ExecuteAction(menuItem.Action); - } return button; } @@ -110,10 +88,11 @@ public partial class CalendarItemCommandBarFlyout : CommandBarFlyout var flyoutItem = new MenuFlyoutItem { Text = GetActionLabel(menuItem.Action), - IsEnabled = menuItem.IsEnabled + IsEnabled = menuItem.IsEnabled, + Command = _executeActionCommand, + CommandParameter = menuItem.Action }; - flyoutItem.Click += (_, _) => ExecuteAction(menuItem.Action); items.Add(flyoutItem); } } @@ -121,7 +100,8 @@ public partial class CalendarItemCommandBarFlyout : CommandBarFlyout private void ExecuteAction(CalendarContextMenuAction action) { - if (Item == null) + // We don't want to trigger any action or hide the flyout if it's a sub menu item. + if (Item == null || (action.ShowAs == null && action.ResponseStatus == null && action.TargetType == null)) return; WeakReferenceMessenger.Default.Send(new CalendarItemContextActionRequestedMessage(Item, action)); diff --git a/Wino.Mail.WinUI/Controls/Calendar/CalendarItemControl.xaml b/Wino.Mail.WinUI/Controls/Calendar/CalendarItemControl.xaml index 2ac8e545..51b113d0 100644 --- a/Wino.Mail.WinUI/Controls/Calendar/CalendarItemControl.xaml +++ b/Wino.Mail.WinUI/Controls/Calendar/CalendarItemControl.xaml @@ -31,9 +31,10 @@ + ShowMode="Auto" /> @@ -80,8 +81,8 @@ + diff --git a/Wino.Mail.WinUI/Controls/Calendar/CalendarItemControl.xaml.cs b/Wino.Mail.WinUI/Controls/Calendar/CalendarItemControl.xaml.cs index ef3bda74..db3ccf54 100644 --- a/Wino.Mail.WinUI/Controls/Calendar/CalendarItemControl.xaml.cs +++ b/Wino.Mail.WinUI/Controls/Calendar/CalendarItemControl.xaml.cs @@ -1,19 +1,20 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using CommunityToolkit.Mvvm.Messaging; -using CommunityToolkit.WinUI; -using Itenso.TimePeriod; +using Microsoft.Extensions.DependencyInjection; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Input; -using Microsoft.UI.Xaml.Media; using Windows.ApplicationModel.DataTransfer; using Wino.Calendar.ViewModels.Data; using Wino.Calendar.ViewModels.Messages; -using Wino.Core.Domain; +using Wino.Core.Domain.Interfaces; +using Wino.Mail.WinUI; namespace Wino.Calendar.Controls; public sealed partial class CalendarItemControl : UserControl { + private readonly ICalendarContextMenuItemService _contextMenuItemService; + // Single tap has a delay to report double taps properly. private bool isSingleTap = false; @@ -44,6 +45,7 @@ public sealed partial class CalendarItemControl : UserControl public CalendarItemControl() { + _contextMenuItemService = WinoApplication.Current.Services.GetRequiredService(); InitializeComponent(); } @@ -141,4 +143,33 @@ public sealed partial class CalendarItemControl : UserControl WeakReferenceMessenger.Default.Send(new CalendarItemRightTappedMessage(CalendarItem)); } + + private void CalendarItemCommandBarFlyout_Opening(object sender, object e) + { + if (sender is not CalendarItemCommandBarFlyout flyout) + { + return; + } + + flyout.Item = CalendarItem; + + if (CalendarItem?.CalendarItem == null) + { + flyout.ClearMenuItems(); + return; + } + + flyout.SetMenuItems(_contextMenuItemService.GetContextMenuItems(CalendarItem.CalendarItem)); + } + + private void CalendarItemCommandBarFlyout_Closed(object sender, object e) + { + if (sender is not CalendarItemCommandBarFlyout flyout) + { + return; + } + + flyout.ClearMenuItems(); + flyout.Item = null; + } } diff --git a/Wino.Mail.WinUI/Views/Calendar/CalendarPage.xaml.cs b/Wino.Mail.WinUI/Views/Calendar/CalendarPage.xaml.cs index 16c6ba10..cc50529a 100644 --- a/Wino.Mail.WinUI/Views/Calendar/CalendarPage.xaml.cs +++ b/Wino.Mail.WinUI/Views/Calendar/CalendarPage.xaml.cs @@ -32,6 +32,7 @@ public sealed partial class CalendarPage : CalendarPageAbstract, ITitleBarSearch private CancellationTokenSource? _searchCancellationTokenSource; private long _calendarTypeSelectorChangedToken; private bool _suppressSelectionResetOnPopupClose; + private bool _hasAttachedNavigationLifetimeEvents; public ObservableCollection SearchSuggestions { get; } = []; @@ -42,13 +43,6 @@ public sealed partial class CalendarPage : CalendarPageAbstract, ITitleBarSearch public CalendarPage() { InitializeComponent(); - _calendarTypeSelectorChangedToken = CalendarToolbar.RegisterSelectedTypeChanged(CalendarTypeSelectorSelectedTypeChanged); - CalendarToolbar.PreviousDateRequested += CalendarToolbarPreviousDateRequested; - CalendarToolbar.NextDateRequested += CalendarToolbarNextDateRequested; - ViewModel.PropertyChanged += ViewModelPropertyChanged; - CalendarShellClient.PropertyChanged += CalendarShellClientPropertyChanged; - CalendarShellClient.StatePersistenceService.StatePropertyChanged += CalendarStatePersistenceServiceChanged; - Unloaded += CalendarPageUnloaded; RefreshCalendarToolbar(); } @@ -61,6 +55,8 @@ public sealed partial class CalendarPage : CalendarPageAbstract, ITitleBarSearch protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); + Bindings.Update(); + AttachNavigationLifetimeEvents(); RefreshCalendarToolbar(); if (e.NavigationMode == NavigationMode.Back && ViewModel.RestoreVisibleState()) @@ -79,6 +75,12 @@ public sealed partial class CalendarPage : CalendarPageAbstract, ITitleBarSearch WeakReferenceMessenger.Default.Send(new LoadCalendarMessage(request)); } + protected override void OnNavigatedFrom(NavigationEventArgs e) + { + base.OnNavigatedFrom(e); + DetachNavigationLifetimeEvents(); + } + public async Task OnTitleBarSearchTextChangedAsync() { _searchCancellationTokenSource?.Cancel(); @@ -272,9 +274,31 @@ public sealed partial class CalendarPage : CalendarPageAbstract, ITitleBarSearch } } - private void CalendarPageUnloaded(object sender, RoutedEventArgs e) + private void AttachNavigationLifetimeEvents() { + if (_hasAttachedNavigationLifetimeEvents) + { + return; + } + + _calendarTypeSelectorChangedToken = CalendarToolbar.RegisterSelectedTypeChanged(CalendarTypeSelectorSelectedTypeChanged); + CalendarToolbar.PreviousDateRequested += CalendarToolbarPreviousDateRequested; + CalendarToolbar.NextDateRequested += CalendarToolbarNextDateRequested; + ViewModel.PropertyChanged += ViewModelPropertyChanged; + CalendarShellClient.PropertyChanged += CalendarShellClientPropertyChanged; + CalendarShellClient.StatePersistenceService.StatePropertyChanged += CalendarStatePersistenceServiceChanged; + _hasAttachedNavigationLifetimeEvents = true; + } + + private void DetachNavigationLifetimeEvents() + { + if (!_hasAttachedNavigationLifetimeEvents) + { + return; + } + CloseQuickEventPopup(clearSelection: true); + Bindings.StopTracking(); CalendarToolbar.UnregisterSelectedTypeChanged(_calendarTypeSelectorChangedToken); CalendarToolbar.PreviousDateRequested -= CalendarToolbarPreviousDateRequested; CalendarToolbar.NextDateRequested -= CalendarToolbarNextDateRequested; @@ -283,7 +307,8 @@ public sealed partial class CalendarPage : CalendarPageAbstract, ITitleBarSearch CalendarShellClient.StatePersistenceService.StatePropertyChanged -= CalendarStatePersistenceServiceChanged; _searchCancellationTokenSource?.Cancel(); _searchCancellationTokenSource?.Dispose(); - Unloaded -= CalendarPageUnloaded; + _searchCancellationTokenSource = null; + _hasAttachedNavigationLifetimeEvents = false; } private async void SaveQuickEventClicked(object sender, RoutedEventArgs e)