Browse Source

Manage Assembly Lists dialog + Create List prompt

Replaces the NotImplementedDialog stub in FileCommands.cs's
ManageAssemblyListsCommand with a real File → Manage Assembly Lists dialog.

Assisted-by: Claude:claude-opus-4-7:Claude Code
pull/3755/head
Siegfried Pammer 2 months ago
parent
commit
4a86e31c58
  1. 18
      ILSpy/Commands/FileCommands.cs
  2. 15
      ILSpy/Views/CreateListDialog.axaml
  3. 58
      ILSpy/Views/CreateListDialog.axaml.cs
  4. 21
      ILSpy/Views/ManageAssemblyListsDialog.axaml
  5. 140
      ILSpy/Views/ManageAssemblyListsDialog.axaml.cs

18
ILSpy/Commands/FileCommands.cs

@ -96,7 +96,23 @@ namespace ILSpy.Commands @@ -96,7 +96,23 @@ namespace ILSpy.Commands
[Shared]
sealed class ManageAssemblyListsCommand : SimpleCommand
{
public override void Execute(object? parameter) => NotImplementedDialog.Show(Resources.ManageAssembly_Lists);
readonly SettingsService settingsService;
[ImportingConstructor]
public ManageAssemblyListsCommand(SettingsService settingsService)
{
this.settingsService = settingsService;
}
public override void Execute(object? parameter)
{
var owner = (global::Avalonia.Application.Current?.ApplicationLifetime
as global::Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime)?.MainWindow;
if (owner == null)
return;
var dlg = new Views.ManageAssemblyListsDialog(settingsService);
_ = dlg.ShowDialog(owner);
}
}
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources._Reload), MenuIcon = "Images/Refresh", MenuCategory = nameof(Resources.Open), MenuOrder = 2, InputGestureText = "F5")]

15
ILSpy/Views/CreateListDialog.axaml

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ILSpy.Views.CreateListDialog"
Width="320" Height="160" CanResize="False"
WindowStartupLocation="CenterOwner"
Title="ILSpy">
<Grid Margin="12,8" RowDefinitions="Auto,Auto,*,Auto">
<TextBlock Grid.Row="0" Text="Enter the name of the list:" Margin="0,0,0,6" />
<TextBox Grid.Row="1" Name="ListNameBox" Margin="0,4" />
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Spacing="6">
<Button Name="OkButton" Content="OK" IsDefault="True" IsEnabled="False" MinWidth="72" />
<Button Name="CancelButton" Content="Cancel" IsCancel="True" MinWidth="72" />
</StackPanel>
</Grid>
</Window>

58
ILSpy/Views/CreateListDialog.axaml.cs

@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
// 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 Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace ILSpy.Views
{
/// <summary>
/// Modal prompt for a single text field — used by ManageAssemblyListsDialog's
/// New / Clone / Rename / Add-Preconfigured flows. Returns the entered name via
/// <see cref="Window.ShowDialog{TResult}"/>'s string result, or <c>null</c> if
/// the user cancelled. Title and initial text are passed in by the caller so the
/// same window backs all four flows.
/// </summary>
public partial class CreateListDialog : Window
{
TextBox listNameBox = null!;
Button okButton = null!;
public CreateListDialog()
{
InitializeComponent();
listNameBox = this.FindControl<TextBox>("ListNameBox")!;
okButton = this.FindControl<Button>("OkButton")!;
listNameBox.TextChanged += (_, _) => okButton.IsEnabled = !string.IsNullOrWhiteSpace(listNameBox.Text);
okButton.Click += (_, _) => Close(listNameBox.Text);
((Button)this.FindControl<Button>("CancelButton")!).Click += (_, _) => Close(null);
}
public CreateListDialog(string title, string? initialText = null) : this()
{
Title = title;
if (!string.IsNullOrEmpty(initialText))
{
listNameBox.Text = initialText;
listNameBox.SelectAll();
}
}
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
}
}

21
ILSpy/Views/ManageAssemblyListsDialog.axaml

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ILSpy.Views.ManageAssemblyListsDialog"
Width="480" Height="350" MinWidth="480" MinHeight="250"
WindowStartupLocation="CenterOwner"
Title="Manage Assembly Lists">
<Grid Margin="12,8" ColumnDefinitions="*,Auto" RowDefinitions="*,Auto">
<ListBox Grid.Row="0" Grid.Column="0" Name="ListsBox" Margin="0,8,8,8" SelectionMode="Single" />
<StackPanel Grid.Row="0" Grid.Column="1" Margin="4,8" Spacing="4" MinWidth="100">
<Button Name="NewButton" Content="_New" />
<Button Name="CloneButton" Content="C_lone" />
<Button Name="RenameButton" Content="R_ename" />
<Button Name="DeleteButton" Content="_Delete" />
<Button Name="ResetButton" Margin="0,12,0,0" Content="_Reset" />
</StackPanel>
<StackPanel Grid.Row="1" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Right" Spacing="6">
<Button Name="SelectButton" Content="Select" IsDefault="True" MinWidth="72" />
<Button Name="CloseButton" Content="Close" IsCancel="True" MinWidth="72" />
</StackPanel>
</Grid>
</Window>

140
ILSpy/Views/ManageAssemblyListsDialog.axaml.cs

@ -0,0 +1,140 @@ @@ -0,0 +1,140 @@
// 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;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using ICSharpCode.ILSpyX;
namespace ILSpy.Views
{
/// <summary>
/// Manage Assembly Lists dialog: list of saved assembly-list names with New / Clone /
/// Rename / Delete / Reset operations + a Select button that swaps the active list.
/// Mirrors WPF's <c>ManageAssemblyListsDialog</c>; all CRUD ops route through the
/// shared <see cref="AssemblyListManager"/>.
/// </summary>
public partial class ManageAssemblyListsDialog : Window
{
readonly SettingsService settingsService;
readonly AssemblyListManager manager;
readonly ListBox listsBox;
public ManageAssemblyListsDialog() : this(NullSettingsService()) { }
public ManageAssemblyListsDialog(SettingsService settingsService)
{
InitializeComponent();
this.settingsService = settingsService;
this.manager = settingsService.AssemblyListManager;
listsBox = this.FindControl<ListBox>("ListsBox")!;
listsBox.ItemsSource = manager.AssemblyLists;
WireButtons();
}
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
// Design-time-only no-op fallback so XAML preview doesn't blow up on the null
// SettingsService when a designer instantiates the dialog without composition.
static SettingsService NullSettingsService()
=> AppEnv.AppComposition.Current.GetExport<SettingsService>();
void WireButtons()
{
this.FindControl<Button>("NewButton")!.Click += async (_, _) => await NewListAsync();
this.FindControl<Button>("CloneButton")!.Click += async (_, _) => await CloneListAsync();
this.FindControl<Button>("RenameButton")!.Click += async (_, _) => await RenameListAsync();
this.FindControl<Button>("DeleteButton")!.Click += (_, _) => DeleteList();
this.FindControl<Button>("ResetButton")!.Click += (_, _) => ResetLists();
this.FindControl<Button>("SelectButton")!.Click += (_, _) => SelectAndClose();
this.FindControl<Button>("CloseButton")!.Click += (_, _) => Close();
}
string? SelectedListName => listsBox.SelectedItem as string;
async Task<string?> PromptAsync(string title, string? initialText = null)
{
var dlg = new CreateListDialog(title, initialText);
return await dlg.ShowDialog<string?>(this);
}
async Task NewListAsync()
{
var name = await PromptAsync("New Assembly List");
if (string.IsNullOrWhiteSpace(name) || manager.AssemblyLists.Contains(name))
return;
var list = manager.CreateList(name);
manager.AddListIfNotExists(list);
}
async Task CloneListAsync()
{
if (SelectedListName is not { } selected)
return;
var name = await PromptAsync("Clone Assembly List");
if (string.IsNullOrWhiteSpace(name) || manager.AssemblyLists.Contains(name))
return;
manager.CloneList(selected, name);
}
async Task RenameListAsync()
{
if (SelectedListName is not { } selected)
return;
var name = await PromptAsync("Rename Assembly List", selected);
if (string.IsNullOrWhiteSpace(name) || name == selected || manager.AssemblyLists.Contains(name))
return;
manager.RenameList(selected, name);
if (settingsService.SessionSettings.ActiveAssemblyList == selected)
settingsService.SessionSettings.ActiveAssemblyList = name;
}
void DeleteList()
{
if (SelectedListName is not { } selected)
return;
int index = manager.AssemblyLists.IndexOf(selected);
manager.DeleteList(selected);
if (manager.AssemblyLists.Count > 0)
{
listsBox.SelectedIndex = Math.Max(0, index - 1);
if (settingsService.SessionSettings.ActiveAssemblyList == selected)
settingsService.SessionSettings.ActiveAssemblyList = manager.AssemblyLists[Math.Max(0, index - 1)];
}
}
void ResetLists()
{
manager.ClearAll();
manager.CreateDefaultAssemblyLists();
if (manager.AssemblyLists.Count > 0)
settingsService.SessionSettings.ActiveAssemblyList = manager.AssemblyLists[0];
}
void SelectAndClose()
{
if (SelectedListName is { } selected)
settingsService.SessionSettings.ActiveAssemblyList = selected;
Close();
}
}
}
Loading…
Cancel
Save