diff --git a/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml b/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml new file mode 100644 index 00000000..69d12455 --- /dev/null +++ b/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml @@ -0,0 +1,7 @@ + + + diff --git a/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml.cs b/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml.cs new file mode 100644 index 00000000..f7cece5e --- /dev/null +++ b/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml.cs @@ -0,0 +1,73 @@ +using Avalonia.Collections; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using LibationAvalonia.ViewModels; +using System; +using System.Reflection; + +namespace LibationAvalonia.Controls +{ + public class DataGridViewCellContextMenuStripNeededEventArgs + { + private static readonly MethodInfo GetCellValueMethod; + static DataGridViewCellContextMenuStripNeededEventArgs() + { + GetCellValueMethod = typeof(DataGridColumn).GetMethod("GetCellValue", BindingFlags.NonPublic | BindingFlags.Instance); + } + + private static string GetCellValue(DataGridColumn column, object item) + => GetCellValueMethod.Invoke(column, new object[] { item, column.ClipboardContentBinding })?.ToString() ?? ""; + + public string CellClipboardContents => GetCellValue(Column, GridEntry); + public DataGridTemplateColumnExt 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 + { + public event EventHandler CellContextMenuStripNeeded; + + private readonly ContextMenu ContextMenu = new(); + private readonly AvaloniaList MenuItems = new(); + + public DataGridTemplateColumnExt() + { + AvaloniaXamlLoader.Load(this); + ContextMenu.Items = MenuItems; + } + + private void Cell_ContextRequested(object sender, ContextRequestedEventArgs e) + { + if (sender is DataGridCell cell && cell.DataContext is GridEntry entry) + { + var args = new DataGridViewCellContextMenuStripNeededEventArgs + { + 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) + { + if (cell.ContextMenu is null) + { + cell.ContextRequested += Cell_ContextRequested; + cell.ContextMenu = ContextMenu; + } + + return base.GenerateElement(cell, dataItem); + } + } +} diff --git a/Source/LibationAvalonia/LibationAvalonia.csproj b/Source/LibationAvalonia/LibationAvalonia.csproj index b31929d4..274e0548 100644 --- a/Source/LibationAvalonia/LibationAvalonia.csproj +++ b/Source/LibationAvalonia/LibationAvalonia.csproj @@ -89,6 +89,9 @@ + + DataGridTemplateColumnExt.axaml + True True diff --git a/Source/LibationAvalonia/Views/ProductsDisplay.axaml b/Source/LibationAvalonia/Views/ProductsDisplay.axaml index 5c3748a3..e2e4d9d5 100644 --- a/Source/LibationAvalonia/Views/ProductsDisplay.axaml +++ b/Source/LibationAvalonia/Views/ProductsDisplay.axaml @@ -16,10 +16,11 @@ AutoGenerateColumns="False" Items="{Binding GridEntries}" CanUserSortColumns="True" + SelectionMode="Single" CanUserReorderColumns="True"> - + - + - + - + @@ -64,7 +58,7 @@ - + @@ -74,9 +68,9 @@ - + - + @@ -86,9 +80,9 @@ - + - + @@ -98,9 +92,9 @@ - + - + @@ -110,9 +104,9 @@ - + - + @@ -122,9 +116,9 @@ - + - + @@ -134,9 +128,9 @@ - + - + @@ -146,9 +140,9 @@ - + - + @@ -158,9 +152,9 @@ - + - + @@ -170,9 +164,9 @@ - + - + @@ -182,9 +176,9 @@ - + - + @@ -194,9 +188,9 @@ - + - + @@ -209,7 +203,7 @@ - + diff --git a/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs b/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs index bd4e7fae..3cac4a9e 100644 --- a/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs +++ b/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs @@ -10,7 +10,7 @@ using LibationAvalonia.Dialogs; using System; using System.Collections.Generic; using System.Linq; -using Avalonia.Interactivity; +using LibationAvalonia.Controls; namespace LibationAvalonia.Views { @@ -53,7 +53,7 @@ namespace LibationAvalonia.Views { column.CustomSortComparer = new RowComparer(column); } - } + } private void RemoveColumn_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) { @@ -71,6 +71,29 @@ namespace LibationAvalonia.Views productsGrid = this.FindControl(nameof(productsGrid)); } + #region Cell Context Menu + + public void ProductsGrid_CellContextMenuStripNeeded(object sender, DataGridViewCellContextMenuStripNeededEventArgs args) + { + if (args.Column.SortMemberPath == "Liberate") + { + + } + else + { + // any non-stop light column + // (except for the Cover column which does not have a context menu) + var menuItem = new MenuItem { Header = "_Copy Cell Contents" }; + + menuItem.Click += async (s, e) + => await Application.Current.Clipboard.SetTextAsync(args.CellClipboardContents); + + args.ContextMenuItems.Add(menuItem); + } + } + + #endregion + #region Column Customizations private void Configure_ColumnCustomization() @@ -96,6 +119,10 @@ 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)) @@ -185,22 +212,6 @@ namespace LibationAvalonia.Views #region Button Click Handlers - public void ContextMenuItem1_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args) - { - var lbe = getBoundEntry(args.Source); - } - public void ContextMenuItem2_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args) - { - var lbe = getBoundEntry(args.Source); - } - public void ContextMenuItem3_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args) - { - var lbe = getBoundEntry(args.Source); - } - - private static LibraryBookEntry getBoundEntry(IInteractive source) - => (source is IStyledElement se && se.DataContext is LibraryBookEntry lbe ? lbe : null); - public void LiberateButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args) { var button = args.Source as Button;