Browse Source

Switch the live assembly list from Manage Assembly Lists

Selecting a list in the dialog only set SessionSettings.ActiveAssemblyList
directly, which merely persists the choice for the next launch — it never
reloaded the tree, so the active list appeared unchanged. Route selection
through AssemblyTreeModel.ActiveListName instead, whose setter reloads the
list (OnActiveListNameChanged -> ShowAssemblyList) and persists the choice.

Also make double-clicking an entry a shortcut for the Select button (both
go through the same activation path).

Assisted-by: Claude:claude-opus-4-8:Claude Code
pull/3755/head
Siegfried Pammer 1 month ago
parent
commit
5f89a84fbc
  1. 65
      ILSpy.Tests/AssemblyList/ManageAssemblyListsSelectTests.cs
  2. 34
      ILSpy/Views/ManageAssemblyListsDialog.axaml.cs

65
ILSpy.Tests/AssemblyList/ManageAssemblyListsSelectTests.cs

@ -0,0 +1,65 @@
// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Headless.NUnit;
using AwesomeAssertions;
using ILSpy;
using ILSpy.AppEnv;
using ILSpy.Views;
using NUnit.Framework;
namespace ICSharpCode.ILSpy.Tests;
/// <summary>
/// Selecting a list in Manage Assembly Lists (the Select button and the double-click shortcut both
/// call the same activation path) must switch the LIVE active list, not merely persist it for the
/// next launch — i.e. it must drive AssemblyTreeModel.ActiveListName, which reloads the tree.
/// </summary>
[TestFixture]
public class ManageAssemblyListsSelectTests
{
[AvaloniaTest]
public async Task Selecting_A_List_Switches_The_Live_Active_List()
{
var (_, vm) = await TestHarness.BootAsync();
var settingsService = AppComposition.Current.GetExport<SettingsService>();
var manager = settingsService.AssemblyListManager;
var current = vm.AssemblyTreeModel.ActiveListName;
// Ensure there is a second, empty list to switch to (the headless fixture seeds one).
var other = "Switch Target " + System.Guid.NewGuid().ToString("N");
manager.AddListIfNotExists(manager.CreateList(other));
other.Should().NotBe(current);
var dialog = new ManageAssemblyListsDialog(settingsService);
dialog.ListsControl.SelectedItem = other;
dialog.ActivateSelectedList();
vm.AssemblyTreeModel.ActiveListName.Should().Be(other,
"selecting a list must switch the live active list (via AssemblyTreeModel.ActiveListName), not just the persisted setting");
settingsService.SessionSettings.ActiveAssemblyList.Should().Be(other,
"and the choice is persisted as a side effect of the model switch");
}
}

34
ILSpy/Views/ManageAssemblyListsDialog.axaml.cs

@ -24,7 +24,9 @@ using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.VisualTree;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
@ -73,6 +75,18 @@ namespace ILSpy.Views
addPreconfigured.Click += (_, _) => ShowPreconfiguredMenu(addPreconfigured); addPreconfigured.Click += (_, _) => ShowPreconfiguredMenu(addPreconfigured);
this.FindControl<Button>("SelectButton")!.Click += (_, _) => SelectAndClose(); this.FindControl<Button>("SelectButton")!.Click += (_, _) => SelectAndClose();
this.FindControl<Button>("CloseButton")!.Click += (_, _) => Close(); this.FindControl<Button>("CloseButton")!.Click += (_, _) => Close();
// Double-clicking an entry is a shortcut for the Select button: activate that list and
// close. Guarded to a real entry so a double-click on empty list space does nothing.
listsBox.DoubleTapped += OnListDoubleTapped;
}
void OnListDoubleTapped(object? sender, TappedEventArgs e)
{
var visual = e.Source as global::Avalonia.Visual;
while (visual is not null and not ListBoxItem)
visual = visual.GetVisualParent();
if (visual is ListBoxItem)
SelectAndClose();
} }
void ShowPreconfiguredMenu(Button anchor) void ShowPreconfiguredMenu(Button anchor)
@ -90,6 +104,9 @@ namespace ILSpy.Views
string? SelectedListName => listsBox.SelectedItem as string; string? SelectedListName => listsBox.SelectedItem as string;
/// <summary>The lists control, exposed for tests to drive the selection.</summary>
internal ListBox ListsControl => listsBox;
async Task<string?> PromptAsync(string title, string? initialText = null) async Task<string?> PromptAsync(string title, string? initialText = null)
{ {
var dlg = new CreateListDialog(title, initialText); var dlg = new CreateListDialog(title, initialText);
@ -151,11 +168,24 @@ namespace ILSpy.Views
void SelectAndClose() void SelectAndClose()
{ {
if (SelectedListName is { } selected) ActivateSelectedList();
settingsService.SessionSettings.ActiveAssemblyList = selected;
Close(); Close();
} }
/// <summary>
/// Switches the live active assembly list to the selected one. Goes through
/// <see cref="AssemblyTree.AssemblyTreeModel.ActiveListName"/> rather than poking the
/// session setting directly, because that setter is what reloads the tree
/// (<c>OnActiveListNameChanged</c> -> <c>ShowAssemblyList</c>) and persists the choice.
/// Setting the session setting alone only takes effect on the next launch.
/// </summary>
internal void ActivateSelectedList()
{
if (SelectedListName is not { } selected)
return;
AppEnv.AppComposition.Current.GetExport<AssemblyTree.AssemblyTreeModel>().ActiveListName = selected;
}
/// <summary> /// <summary>
/// The list of preconfigured assembly lists offered by the "Add preconfigured list..." /// The list of preconfigured assembly lists offered by the "Add preconfigured list..."
/// menu: the three GAC-based framework lists (only when a GAC is actually present, i.e. /// menu: the three GAC-based framework lists (only when a GAC is actually present, i.e.

Loading…
Cancel
Save