Add multi-select context menu support (rmcrackan/Libation#1195)
This commit is contained in:
parent
bfcd226795
commit
c77f2e2162
10 changed files with 455 additions and 229 deletions
|
|
@ -2,6 +2,7 @@
|
|||
using Avalonia.Controls;
|
||||
using LibationUiBase.GridView;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace LibationAvalonia.Controls
|
||||
|
|
@ -12,11 +13,13 @@ namespace LibationAvalonia.Controls
|
|||
private static readonly ContextMenu ContextMenu = new();
|
||||
private static readonly AvaloniaList<Control> MenuItems = new();
|
||||
private static readonly PropertyInfo OwningColumnProperty;
|
||||
private static readonly PropertyInfo OwningGridProperty;
|
||||
|
||||
static DataGridContextMenus()
|
||||
{
|
||||
ContextMenu.ItemsSource = MenuItems;
|
||||
OwningColumnProperty = typeof(DataGridCell).GetProperty("OwningColumn", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
OwningGridProperty = typeof(DataGridColumn).GetProperty("OwningGrid", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
}
|
||||
|
||||
public static void AttachContextMenu(this DataGridCell cell)
|
||||
|
|
@ -30,19 +33,35 @@ namespace LibationAvalonia.Controls
|
|||
|
||||
private static void Cell_ContextRequested(object sender, ContextRequestedEventArgs e)
|
||||
{
|
||||
if (sender is DataGridCell cell && cell.DataContext is IGridEntry entry)
|
||||
if (sender is DataGridCell cell &&
|
||||
cell.DataContext is IGridEntry clickedEntry &&
|
||||
OwningColumnProperty.GetValue(cell) is DataGridColumn column &&
|
||||
OwningGridProperty.GetValue(column) is DataGrid grid)
|
||||
{
|
||||
var allSelected = grid.SelectedItems.OfType<IGridEntry>().ToArray();
|
||||
var clickedIndex = Array.IndexOf(allSelected, clickedEntry);
|
||||
if (clickedIndex == -1)
|
||||
{
|
||||
//User didn't right-click on a selected cell
|
||||
grid.SelectedItem = clickedEntry;
|
||||
allSelected = [clickedEntry];
|
||||
}
|
||||
else if (clickedIndex > 0)
|
||||
{
|
||||
//Ensure the clicked entry is first in the list
|
||||
(allSelected[0], allSelected[clickedIndex]) = (allSelected[clickedIndex], allSelected[0]);
|
||||
}
|
||||
|
||||
var args = new DataGridCellContextMenuStripNeededEventArgs
|
||||
{
|
||||
Column = OwningColumnProperty.GetValue(cell) as DataGridColumn,
|
||||
GridEntry = entry,
|
||||
Column = column,
|
||||
Grid = grid,
|
||||
GridEntries = allSelected,
|
||||
ContextMenu = ContextMenu
|
||||
};
|
||||
|
||||
args.ContextMenuItems.Clear();
|
||||
|
||||
CellContextMenuStripNeeded?.Invoke(sender, args);
|
||||
|
||||
e.Handled = args.ContextMenuItems.Count == 0;
|
||||
}
|
||||
else
|
||||
|
|
@ -61,10 +80,37 @@ namespace LibationAvalonia.Controls
|
|||
private static string GetCellValue(DataGridColumn column, object item)
|
||||
=> GetCellValueMethod.Invoke(column, new object[] { item, column.ClipboardContentBinding })?.ToString() ?? "";
|
||||
|
||||
public string CellClipboardContents => GetCellValue(Column, GridEntry);
|
||||
public DataGridColumn Column { get; init; }
|
||||
public IGridEntry GridEntry { get; init; }
|
||||
public ContextMenu ContextMenu { get; init; }
|
||||
public string CellClipboardContents => GetCellValue(Column, GridEntries[0]);
|
||||
public string GetRowClipboardContents()
|
||||
{
|
||||
if (GridEntries is null || GridEntries.Length == 0)
|
||||
return string.Empty;
|
||||
else if (GridEntries.Length == 1)
|
||||
return HeaderNames + Environment.NewLine + GetRowClipboardContents(GridEntries[0]);
|
||||
else
|
||||
return string.Join(Environment.NewLine, GridEntries.Select(GetRowClipboardContents).Prepend(HeaderNames));
|
||||
}
|
||||
|
||||
private string HeaderNames
|
||||
=> string.Join("\t",
|
||||
Grid.Columns
|
||||
.Where(c => c.IsVisible)
|
||||
.OrderBy(c => c.DisplayIndex)
|
||||
.Select(c => RemoveLineBreaks(c.Header.ToString())));
|
||||
|
||||
private static string RemoveLineBreaks(string text)
|
||||
=> text.Replace("\r\n", "").Replace('\r', ' ').Replace('\n', ' ');
|
||||
|
||||
private string GetRowClipboardContents(IGridEntry gridEntry)
|
||||
{
|
||||
var contents = Grid.Columns.Where(c => c.IsVisible).OrderBy(c => c.DisplayIndex).Select(c => RemoveLineBreaks(GetCellValue(c, gridEntry))).ToArray();
|
||||
return string.Join("\t", contents);
|
||||
}
|
||||
|
||||
public required DataGrid Grid { get; init; }
|
||||
public required DataGridColumn Column { get; init; }
|
||||
public required IGridEntry[] GridEntries { get; init; }
|
||||
public required ContextMenu ContextMenu { get; init; }
|
||||
public AvaloniaList<Control> ContextMenuItems
|
||||
=> ContextMenu.ItemsSource as AvaloniaList<Control>;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue