From eb03555b7fa0aee6b9fc62716673783f9e15d40d Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Fri, 8 May 2026 17:45:57 +0200 Subject: [PATCH] Drop redundant Copy in metadata grid context menu Avalonia DataGrid surfaces a per-cell Copy in its default cell context menu, so seeding our own at the top of the built menu produced a duplicate "Copy" entry. Revert the seed; cancel our menu when no MEF entries are visible (the built-in cell menu still shows). Assisted-by: Claude:claude-opus-4-7:Claude Code --- ILSpy/Views/MetadataTablePage.axaml.cs | 63 ++++---------------------- 1 file changed, 10 insertions(+), 53 deletions(-) diff --git a/ILSpy/Views/MetadataTablePage.axaml.cs b/ILSpy/Views/MetadataTablePage.axaml.cs index e83052e14..87bd4ad86 100644 --- a/ILSpy/Views/MetadataTablePage.axaml.cs +++ b/ILSpy/Views/MetadataTablePage.axaml.cs @@ -25,7 +25,6 @@ using Avalonia; using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Input; -using Avalonia.Input.Platform; using Avalonia.Markup.Xaml; using Avalonia.VisualTree; @@ -123,63 +122,21 @@ 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) { - menu.Items.Add(new Separator()); - foreach (var item in built.Items.Cast().ToArray()) - { - built.Items.Remove(item); - menu.Items.Add(item); - } + // No MEF entries are visible for this click. Avalonia DataGrid's default + // per-cell context menu still surfaces Copy, so cancel ours rather than + // stack a redundant duplicate on top of it. + e.Cancel = true; + return; } - } - - 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++) + menu.Items.Clear(); + foreach (var item in built.Items.Cast().ToArray()) { - 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()); - } + built.Items.Remove(item); + menu.Items.Add(item); } - return sb.ToString(); } void InitializeComponent() => AvaloniaXamlLoader.Load(this);