From a7bf30954dbea2f7c4232d76ae8e8af7b5ea0a05 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sat, 31 Dec 2022 21:09:30 -0700 Subject: [PATCH] Fix null file bug and add context menu to my ratings column --- .../Controls/DataGridCheckBoxColumnExt.axaml | 5 -- ....axaml.cs => DataGridCheckBoxColumnExt.cs} | 5 +- ...mnExt.axaml.cs => DataGridContextMenus.cs} | 62 +++++++------ ...umn.axaml.cs => DataGridMyRatingColumn.cs} | 36 +++----- .../Controls/DataGridTemplateColumnExt.axaml | 7 -- .../Controls/DataGridTemplateColumnExt.cs | 15 ++++ .../Controls/MyRatingCellEditor.axaml | 86 ++++++++++--------- .../Controls/MyRatingCellEditor.axaml.cs | 18 ++-- .../Controls/MyRatingGridColumn.axaml | 8 -- .../Dialogs/AccountsDialog.axaml.cs | 4 +- .../Dialogs/ImageDisplayDialog.axaml.cs | 4 +- .../Views/MainWindow.Export.cs | 2 +- .../Views/ProductsDisplay.axaml | 3 +- .../Views/ProductsDisplay.axaml.cs | 7 +- 14 files changed, 118 insertions(+), 144 deletions(-) delete mode 100644 Source/LibationAvalonia/Controls/DataGridCheckBoxColumnExt.axaml rename Source/LibationAvalonia/Controls/{DataGridCheckBoxColumnExt.axaml.cs => DataGridCheckBoxColumnExt.cs} (79%) rename Source/LibationAvalonia/Controls/{DataGridTemplateColumnExt.axaml.cs => DataGridContextMenus.cs} (67%) rename Source/LibationAvalonia/Controls/{MyRatingGridColumn.axaml.cs => DataGridMyRatingColumn.cs} (53%) delete mode 100644 Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml create mode 100644 Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.cs delete mode 100644 Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml diff --git a/Source/LibationAvalonia/Controls/DataGridCheckBoxColumnExt.axaml b/Source/LibationAvalonia/Controls/DataGridCheckBoxColumnExt.axaml deleted file mode 100644 index d51e730d..00000000 --- a/Source/LibationAvalonia/Controls/DataGridCheckBoxColumnExt.axaml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/Source/LibationAvalonia/Controls/DataGridCheckBoxColumnExt.axaml.cs b/Source/LibationAvalonia/Controls/DataGridCheckBoxColumnExt.cs similarity index 79% rename from Source/LibationAvalonia/Controls/DataGridCheckBoxColumnExt.axaml.cs rename to Source/LibationAvalonia/Controls/DataGridCheckBoxColumnExt.cs index 2c686498..0bf914c9 100644 --- a/Source/LibationAvalonia/Controls/DataGridCheckBoxColumnExt.axaml.cs +++ b/Source/LibationAvalonia/Controls/DataGridCheckBoxColumnExt.cs @@ -1,10 +1,11 @@ -using Avalonia.Controls; +using Avalonia.Controls; using LibationAvalonia.ViewModels; using System; +using System.Linq; namespace LibationAvalonia.Controls { - public partial class DataGridCheckBoxColumnExt : DataGridCheckBoxColumn + public class DataGridCheckBoxColumnExt : DataGridCheckBoxColumn { protected override IControl GenerateEditingElementDirect(DataGridCell cell, object dataItem) { diff --git a/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml.cs b/Source/LibationAvalonia/Controls/DataGridContextMenus.cs similarity index 67% rename from Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml.cs rename to Source/LibationAvalonia/Controls/DataGridContextMenus.cs index b46fac89..37044c51 100644 --- a/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml.cs +++ b/Source/LibationAvalonia/Controls/DataGridContextMenus.cs @@ -1,12 +1,11 @@ -using Avalonia.Collections; +using Avalonia.Collections; using Avalonia.Controls; -using Avalonia.Markup.Xaml; using LibationAvalonia.ViewModels; using System; using System.Reflection; namespace LibationAvalonia.Controls -{ +{ public class DataGridCellContextMenuStripNeededEventArgs { private static readonly MethodInfo GetCellValueMethod; @@ -19,55 +18,54 @@ namespace LibationAvalonia.Controls => GetCellValueMethod.Invoke(column, new object[] { item, column.ClipboardContentBinding })?.ToString() ?? ""; public string CellClipboardContents => GetCellValue(Column, GridEntry); - public DataGridTemplateColumnExt Column { get; init; } + public DataGridColumn Column { get; init; } public GridEntry GridEntry { get; init; } public ContextMenu ContextMenu { get; init; } public AvaloniaList ContextMenuItems => ContextMenu.Items as AvaloniaList; } - public partial class DataGridTemplateColumnExt : DataGridTemplateColumn + internal static class DataGridContextMenus { - public event EventHandler CellContextMenuStripNeeded; - + public static event EventHandler CellContextMenuStripNeeded; private static readonly ContextMenu ContextMenu = new(); - private static readonly AvaloniaList MenuItems = new(); + private static readonly AvaloniaList MenuItems = new(); + private static readonly PropertyInfo OwningColumnProperty; - public DataGridTemplateColumnExt() + static DataGridContextMenus() { - AvaloniaXamlLoader.Load(this); ContextMenu.Items = MenuItems; + OwningColumnProperty = typeof(DataGridCell).GetProperty("OwningColumn", BindingFlags.Instance | BindingFlags.NonPublic); } - private void Cell_ContextRequested(object sender, ContextRequestedEventArgs e) - { - if (sender is DataGridCell cell && cell.DataContext is GridEntry entry) - { - var args = new DataGridCellContextMenuStripNeededEventArgs - { - Column = this, - GridEntry = entry, - ContextMenu = ContextMenu - }; - args.ContextMenuItems.Clear(); - - CellContextMenuStripNeeded?.Invoke(sender, args); - - e.Handled = args.ContextMenuItems.Count == 0; - } - else - e.Handled = true; - } - - protected override IControl GenerateElement(DataGridCell cell, object dataItem) + public static void AttachContextMenuToCell(this DataGridCell cell) { if (cell.ContextMenu is null) { cell.ContextRequested += Cell_ContextRequested; cell.ContextMenu = ContextMenu; } + } - return base.GenerateElement(cell, dataItem); + private static void Cell_ContextRequested(object sender, ContextRequestedEventArgs e) + { + if (sender is DataGridCell cell && cell.DataContext is GridEntry entry) + { + var args = new DataGridCellContextMenuStripNeededEventArgs + { + Column = OwningColumnProperty.GetValue(cell) as DataGridColumn, + GridEntry = entry, + ContextMenu = ContextMenu + }; + + args.ContextMenuItems.Clear(); + + CellContextMenuStripNeeded?.Invoke(sender, args); + + e.Handled = args.ContextMenuItems.Count == 0; + } + else + e.Handled = true; } } } diff --git a/Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml.cs b/Source/LibationAvalonia/Controls/DataGridMyRatingColumn.cs similarity index 53% rename from Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml.cs rename to Source/LibationAvalonia/Controls/DataGridMyRatingColumn.cs index 94a35bf7..d3731e4a 100644 --- a/Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml.cs +++ b/Source/LibationAvalonia/Controls/DataGridMyRatingColumn.cs @@ -1,17 +1,15 @@ -using Avalonia; +using Avalonia; using Avalonia.Controls; using Avalonia.Interactivity; -using Avalonia.Markup.Xaml; using DataLayer; namespace LibationAvalonia.Controls { - public partial class MyRatingGridColumn : DataGridBoundColumn + public class DataGridMyRatingColumn : DataGridBoundColumn { private static Rating DefaultRating => new Rating(0, 0, 0); - public MyRatingGridColumn() + public DataGridMyRatingColumn() { - AvaloniaXamlLoader.Load(this); BindingTarget = MyRatingCellEditor.RatingProperty; } @@ -20,40 +18,26 @@ namespace LibationAvalonia.Controls var myRatingElement = new MyRatingCellEditor { Name = "CellMyRatingDisplay", - HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Left, - VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, - IsEditingMode = false, - Margin = new Thickness(3), - IsEnabled = false + IsEditingMode = false }; - //Create a panel that fills the cell to host the rating tool tip - var panel = new Panel - { - Background = Avalonia.Media.Brushes.Transparent, - HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Stretch, - VerticalAlignment = Avalonia.Layout.VerticalAlignment.Stretch, - }; - panel.Children.Add(myRatingElement); - - ToolTip.SetTip(panel, "Click to change ratings"); + ToolTip.SetTip(myRatingElement, "Click to change ratings"); + cell?.AttachContextMenuToCell(); if (Binding != null) { myRatingElement.Bind(BindingTarget, Binding); } - return panel; + + return myRatingElement; } protected override IControl GenerateEditingElementDirect(DataGridCell cell, object dataItem) { var myRatingElement = new MyRatingCellEditor { - Name = "CellMyRatingCellEditor", - HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Left, - VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, - IsEditingMode = true, - Margin = new Thickness(3) + Name = "CellMyRatingEditor", + IsEditingMode = true }; return myRatingElement; diff --git a/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml b/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml deleted file mode 100644 index 69d12455..00000000 --- a/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.cs b/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.cs new file mode 100644 index 00000000..58f94ff3 --- /dev/null +++ b/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.cs @@ -0,0 +1,15 @@ +using Avalonia.Controls; +using System; +using System.Linq; + +namespace LibationAvalonia.Controls +{ + public partial class DataGridTemplateColumnExt : DataGridTemplateColumn + { + protected override IControl GenerateElement(DataGridCell cell, object dataItem) + { + cell?.AttachContextMenuToCell(); + return base.GenerateElement(cell, dataItem); + } + } +} diff --git a/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml index 67d7138f..aa2e50f6 100644 --- a/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml +++ b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml @@ -2,51 +2,53 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" + mc:Ignorable="d" d:DesignWidth="115" d:DesignHeight="80" x:Class="LibationAvalonia.Controls.MyRatingCellEditor"> - - - - - - - - - + + + + + + - - - - - - - - - + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs index f0c584ab..3c7e889f 100644 --- a/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs +++ b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs @@ -14,11 +14,8 @@ namespace LibationAvalonia.Controls AvaloniaProperty.Register(nameof(Rating)); public bool IsEditingMode { get; set; } - public Rating Rating - { - get { return GetValue(RatingProperty); } - set { SetValue(RatingProperty, value); } - } + public Rating Rating { get => GetValue(RatingProperty); set => SetValue(RatingProperty, value); } + public MyRatingCellEditor() { InitializeComponent(); @@ -44,16 +41,17 @@ namespace LibationAvalonia.Controls foreach (TextBlock star in panelStory.Children) star.Tag = star.Text = Rating.StoryRating > rating++ ? SOLID_STAR : blankValue; - SetVisible(IsEditingMode); + SetVisible(); } base.OnPropertyChanged(change); } - private void SetVisible(bool allVisible) + private void SetVisible() { - tblockOverall.IsVisible = panelOverall.IsVisible = allVisible || Rating?.OverallRating > 0; - tblockPerform.IsVisible = panelPerform.IsVisible = allVisible || Rating?.PerformanceRating > 0; - tblockStory.IsVisible = panelStory.IsVisible = allVisible || Rating?.StoryRating > 0; + ratingsGrid.IsEnabled = IsEditingMode; + tblockOverall.IsVisible = panelOverall.IsVisible = IsEditingMode || Rating?.OverallRating > 0; + tblockPerform.IsVisible = panelPerform.IsVisible = IsEditingMode || Rating?.PerformanceRating > 0; + tblockStory.IsVisible = panelStory.IsVisible = IsEditingMode || Rating?.StoryRating > 0; } public void Panel_PointerExited(object sender, Avalonia.Input.PointerEventArgs e) diff --git a/Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml b/Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml deleted file mode 100644 index 3c77bb14..00000000 --- a/Source/LibationAvalonia/Controls/MyRatingGridColumn.axaml +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml.cs index eab179ea..9dfc6e3f 100644 --- a/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml.cs @@ -131,7 +131,7 @@ namespace LibationAvalonia.Dialogs var selectedFiles = await StorageProvider.OpenFilePickerAsync(openFileDialogOptions); var selectedFile = selectedFiles.SingleOrDefault(); - if (!selectedFile.TryGetUri(out var uri)) return; + if (selectedFile?.TryGetUri(out var uri) is not true) return; try { @@ -291,7 +291,7 @@ namespace LibationAvalonia.Dialogs var selectedFile = await StorageProvider.SaveFilePickerAsync(options); - if (!selectedFile.TryGetUri(out var uri)) return; + if (selectedFile?.TryGetUri(out var uri) is not true) return; try { diff --git a/Source/LibationAvalonia/Dialogs/ImageDisplayDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/ImageDisplayDialog.axaml.cs index 5d6f444e..f6014fe2 100644 --- a/Source/LibationAvalonia/Dialogs/ImageDisplayDialog.axaml.cs +++ b/Source/LibationAvalonia/Dialogs/ImageDisplayDialog.axaml.cs @@ -51,7 +51,7 @@ namespace LibationAvalonia.Dialogs { Title = $"Save Sover Image", SuggestedStartLocation = new Avalonia.Platform.Storage.FileIO.BclStorageFolder(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)), - SuggestedFileName = $"{PictureFileName}.jpg", + SuggestedFileName = PictureFileName, DefaultExtension = "jpg", ShowOverwritePrompt = true, FileTypeChoices = new FilePickerFileType[] @@ -62,7 +62,7 @@ namespace LibationAvalonia.Dialogs var selectedFile = await StorageProvider.SaveFilePickerAsync(options); - if (!selectedFile.TryGetUri(out var uri)) return; + if (selectedFile?.TryGetUri(out var uri) is not true) return; try { diff --git a/Source/LibationAvalonia/Views/MainWindow.Export.cs b/Source/LibationAvalonia/Views/MainWindow.Export.cs index f5d903be..4864fa3e 100644 --- a/Source/LibationAvalonia/Views/MainWindow.Export.cs +++ b/Source/LibationAvalonia/Views/MainWindow.Export.cs @@ -34,7 +34,7 @@ namespace LibationAvalonia.Views var selectedFile = await StorageProvider.SaveFilePickerAsync(options); - if (!selectedFile.TryGetUri(out var uri)) return; + if (selectedFile?.TryGetUri(out var uri) is not true) return; var ext = System.IO.Path.GetExtension(uri.LocalPath); switch (ext) diff --git a/Source/LibationAvalonia/Views/ProductsDisplay.axaml b/Source/LibationAvalonia/Views/ProductsDisplay.axaml index 0a86d97f..28967546 100644 --- a/Source/LibationAvalonia/Views/ProductsDisplay.axaml +++ b/Source/LibationAvalonia/Views/ProductsDisplay.axaml @@ -160,9 +160,8 @@ + - - diff --git a/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs b/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs index 8c479f94..d6f7e74f 100644 --- a/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs +++ b/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs @@ -71,6 +71,7 @@ namespace LibationAvalonia.Views AvaloniaXamlLoader.Load(this); productsGrid = this.FindControl(nameof(productsGrid)); + DataGridContextMenus.CellContextMenuStripNeeded += ProductsGrid_CellContextMenuStripNeeded; } #region Cell Context Menu @@ -121,7 +122,7 @@ namespace LibationAvalonia.Views var selectedFiles = await this.GetParentWindow().StorageProvider.OpenFilePickerAsync(openFileDialogOptions); var selectedFile = selectedFiles.SingleOrDefault(); - if (selectedFile.TryGetUri(out var uri)) + if (selectedFile?.TryGetUri(out var uri) is true) FilePathCache.Insert(entry.AudibleProductId, uri.LocalPath); } catch (Exception ex) @@ -179,10 +180,6 @@ namespace LibationAvalonia.Views foreach (var column in productsGrid.Columns) { - //Wire up column context menu - if (column is DataGridTemplateColumnExt tc) - tc.CellContextMenuStripNeeded += ProductsGrid_CellContextMenuStripNeeded; - var itemName = column.SortMemberPath; if (itemName == nameof(GridEntry.Remove))