Browse Source

Keep metadata grid context menu populated on plain cells

Right-click on a non-token cell was producing nothing because the
GoToToken entry hides itself there and ContextMenuProvider.Build then
returned null, cancelling the menu. Always seed a Copy entry (TSV row
dump matching DataGrid's built-in Ctrl+C behaviour) at the top of the
built menu; MEF entries follow after a separator when applicable.

Assisted-by: Claude:claude-opus-4-7:Claude Code
pull/3755/head
Siegfried Pammer 2 months ago
parent
commit
20fab5a383
  1. 60
      ILSpy/Views/MetadataTablePage.axaml.cs

60
ILSpy/Views/MetadataTablePage.axaml.cs

@ -25,6 +25,7 @@ using Avalonia; @@ -25,6 +25,7 @@ using Avalonia;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Markup.Xaml;
using Avalonia.VisualTree;
@ -122,18 +123,63 @@ namespace ILSpy.Views @@ -122,18 +123,63 @@ namespace ILSpy.Views
DataGrid = grid,
OriginalSource = hoveredCell,
};
menu.Items.Clear();
// Always-available Copy. Avalonia DataGrid's built-in Ctrl+C copies the active
// selection as TSV; mirror that here so right-click in a plain column cell still
// produces a usable menu (the GoToToken entry shows only on token-kind cells).
var copyItem = new MenuItem {
Header = "Copy",
InputGesture = new KeyGesture(Key.C, KeyModifiers.Control),
IsEnabled = grid?.SelectedItem != null,
};
copyItem.Click += async (_, _) => {
if (grid is null)
return;
var topLevel = TopLevel.GetTopLevel(grid);
var clipboard = topLevel?.Clipboard;
if (clipboard is null)
return;
var text = BuildClipboardText(grid);
if (!string.IsNullOrEmpty(text))
await clipboard.SetTextAsync(text);
};
menu.Items.Add(copyItem);
var built = ContextMenuProvider.Build(contextMenuEntries, context);
if (built == null)
if (built != null)
{
e.Cancel = true;
return;
menu.Items.Add(new Separator());
foreach (var item in built.Items.Cast<Control>().ToArray())
{
built.Items.Remove(item);
menu.Items.Add(item);
}
}
menu.Items.Clear();
foreach (var item in built.Items.Cast<Control>().ToArray())
}
static string BuildClipboardText(DataGrid grid)
{
// Tab-separated row dump for the selected item — same shape DataGrid's built-in
// Ctrl+C produces. Walk every column so the user sees the full row state, not
// only the cell under the pointer.
if (grid.SelectedItem is not { } row)
return string.Empty;
var sb = new System.Text.StringBuilder();
for (int i = 0; i < grid.Columns.Count; i++)
{
built.Items.Remove(item);
menu.Items.Add(item);
if (i > 0)
sb.Append('\t');
var col = grid.Columns[i];
if (col is DataGridTextColumn text && text.Binding is global::Avalonia.Data.Binding b
&& b.Path is { } path
&& row.GetType().GetProperty(path) is { } prop)
{
var v = prop.GetValue(row);
sb.Append(v?.ToString());
}
}
return sb.ToString();
}
void InitializeComponent() => AvaloniaXamlLoader.Load(this);

Loading…
Cancel
Save