Browse Source

Get rid of singletons, replace with DI: MainWindow, Settings and Language service

pull/3314/head
tom-englert 8 months ago
parent
commit
560d89a42f
  1. 6
      ILSpy.ReadyToRun/ReadyToRunDisassembler.cs
  2. 12
      ILSpy.ReadyToRun/ReadyToRunLanguage.cs
  3. 2
      ILSpy.Tests/Analyzers/MemberImplementsInterfaceAnalyzerTests.cs
  4. 2
      ILSpy.Tests/Analyzers/MethodUsesAnalyzerTests.cs
  5. 2
      ILSpy.Tests/Analyzers/TypeUsedByAnalyzerTests.cs
  6. 15
      ILSpy/AboutPage.cs
  7. 21
      ILSpy/Analyzers/AnalyzeCommand.cs
  8. 2
      ILSpy/Analyzers/AnalyzerSearchTreeNode.cs
  9. 14
      ILSpy/Analyzers/AnalyzerTreeNode.cs
  10. 5
      ILSpy/Analyzers/AnalyzerTreeViewModel.cs
  11. 15
      ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs
  12. 7
      ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs
  13. 5
      ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs
  14. 5
      ILSpy/Analyzers/TreeNodes/AnalyzedModuleTreeNode.cs
  15. 7
      ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs
  16. 5
      ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs
  17. 16
      ILSpy/App.xaml.cs
  18. 53
      ILSpy/AssemblyTree/AssemblyTreeModel.cs
  19. 9
      ILSpy/Commands/CheckForUpdatesCommand.cs
  20. 25
      ILSpy/Commands/DecompileAllCommand.cs
  21. 8
      ILSpy/Commands/DisassembleAllCommand.cs
  22. 2
      ILSpy/Commands/ExitCommand.cs
  23. 20
      ILSpy/Commands/GeneratePdbContextMenuEntry.cs
  24. 37
      ILSpy/Commands/ILSpyCommands.cs
  25. 6
      ILSpy/Commands/ManageAssemblyListsCommand.cs
  26. 2
      ILSpy/Commands/OpenFromGacCommand.cs
  27. 7
      ILSpy/Commands/Pdb2XmlCommand.cs
  28. 11
      ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs
  29. 11
      ILSpy/Commands/SaveCodeContextMenuEntry.cs
  30. 12
      ILSpy/Commands/SaveCommand.cs
  31. 9
      ILSpy/Commands/SelectPdbContextMenuEntry.cs
  32. 8
      ILSpy/Commands/SetThemeCommand.cs
  33. 9
      ILSpy/Commands/SortAssemblyListCommand.cs
  34. 3
      ILSpy/ContextMenuEntry.cs
  35. 36
      ILSpy/Docking/DockWorkspace.cs
  36. 7
      ILSpy/ExtensionMethods.cs
  37. 4
      ILSpy/Languages/CSharpILMixedLanguage.cs
  38. 38
      ILSpy/Languages/CSharpLanguage.cs
  39. 6
      ILSpy/Languages/ILLanguage.cs
  40. 8
      ILSpy/Languages/Language.cs
  41. 18
      ILSpy/Languages/LanguageService.cs
  42. 10
      ILSpy/MainWindow.xaml
  43. 59
      ILSpy/MainWindow.xaml.cs
  44. 16
      ILSpy/MainWindowViewModel.cs
  45. 2
      ILSpy/Metadata/CorTables/EventTableTreeNode.cs
  46. 2
      ILSpy/Metadata/CorTables/FieldTableTreeNode.cs
  47. 2
      ILSpy/Metadata/CorTables/MethodTableTreeNode.cs
  48. 2
      ILSpy/Metadata/CorTables/PropertyTableTreeNode.cs
  49. 2
      ILSpy/Metadata/CorTables/TypeDefTableTreeNode.cs
  50. 2
      ILSpy/Metadata/DebugMetadataTablesTreeNode.cs
  51. 5
      ILSpy/Metadata/MetadataProtocolHandler.cs
  52. 2
      ILSpy/Metadata/MetadataTablesTreeNode.cs
  53. 17
      ILSpy/Options/OptionsDialog.xaml.cs
  54. 4
      ILSpy/Options/OptionsDialogViewModel.cs
  55. 64
      ILSpy/Search/SearchPane.xaml.cs
  56. 9
      ILSpy/Search/SearchPaneModel.cs
  57. 4
      ILSpy/Search/SearchResultFactory.cs
  58. 3
      ILSpy/SolutionWriter.cs
  59. 2
      ILSpy/TaskHelper.cs
  60. 60
      ILSpy/TextView/DecompilerTextView.cs
  61. 13
      ILSpy/TextView/DocumentationUIBuilder.cs
  62. 32
      ILSpy/Themes/WindowStyleManagerBehavior.cs
  63. 11
      ILSpy/TreeNodes/AssemblyListTreeNode.cs
  64. 4
      ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
  65. 21
      ILSpy/TreeNodes/AssemblyTreeNode.cs
  66. 2
      ILSpy/TreeNodes/DerivedTypesEntryNode.cs
  67. 6
      ILSpy/TreeNodes/EventTreeNode.cs
  68. 6
      ILSpy/TreeNodes/FieldTreeNode.cs
  69. 28
      ILSpy/TreeNodes/ILSpyTreeNode.cs
  70. 8
      ILSpy/TreeNodes/MethodTreeNode.cs
  71. 8
      ILSpy/TreeNodes/PropertyTreeNode.cs
  72. 2
      ILSpy/TreeNodes/ReferenceFolderTreeNode.cs
  73. 3
      ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs
  74. 6
      ILSpy/TreeNodes/TypeTreeNode.cs
  75. 15
      ILSpy/Util/MenuService.cs
  76. 9
      ILSpy/Util/SettingsService.cs
  77. 18
      ILSpy/ViewModels/ManageAssemblyListsViewModel.cs
  78. 23
      ILSpy/ViewModels/TabPageModel.cs
  79. 20
      ILSpy/Views/DebugSteps.xaml.cs
  80. 4
      ILSpy/Views/ManageAssemblyLIstsDialog.xaml.cs
  81. 5
      TestPlugin/MainMenuCommand.cs

6
ILSpy.ReadyToRun/ReadyToRunDisassembler.cs

@ -38,12 +38,14 @@ namespace ICSharpCode.ILSpy.ReadyToRun
private readonly ITextOutput output; private readonly ITextOutput output;
private readonly ReadyToRunReader reader; private readonly ReadyToRunReader reader;
private readonly RuntimeFunction runtimeFunction; private readonly RuntimeFunction runtimeFunction;
private readonly SettingsService settingsService;
public ReadyToRunDisassembler(ITextOutput output, ReadyToRunReader reader, RuntimeFunction runtimeFunction) public ReadyToRunDisassembler(ITextOutput output, ReadyToRunReader reader, RuntimeFunction runtimeFunction, SettingsService settingsService)
{ {
this.output = output; this.output = output;
this.reader = reader; this.reader = reader;
this.runtimeFunction = runtimeFunction; this.runtimeFunction = runtimeFunction;
this.settingsService = settingsService;
} }
public void Disassemble(PEFile currentFile, int bitness, ulong address, bool showMetadataTokens, bool showMetadataTokensInBase10) public void Disassemble(PEFile currentFile, int bitness, ulong address, bool showMetadataTokens, bool showMetadataTokensInBase10)
@ -51,7 +53,7 @@ namespace ICSharpCode.ILSpy.ReadyToRun
ReadyToRunMethod readyToRunMethod = runtimeFunction.Method; ReadyToRunMethod readyToRunMethod = runtimeFunction.Method;
WriteCommentLine(readyToRunMethod.SignatureString); WriteCommentLine(readyToRunMethod.SignatureString);
var options = SettingsService.Instance.GetSettings<ReadyToRunOptions>(); var options = settingsService.GetSettings<ReadyToRunOptions>();
if (options.IsShowGCInfo) if (options.IsShowGCInfo)
{ {

12
ILSpy.ReadyToRun/ReadyToRunLanguage.cs

@ -38,6 +38,10 @@ using ICSharpCode.ILSpyX;
using ILCompiler.Reflection.ReadyToRun; using ILCompiler.Reflection.ReadyToRun;
using TomsToolbox.Composition;
using MetadataReader = System.Reflection.Metadata.MetadataReader;
namespace ICSharpCode.ILSpy.ReadyToRun namespace ICSharpCode.ILSpy.ReadyToRun
{ {
#if STRESS #if STRESS
@ -97,7 +101,7 @@ namespace ICSharpCode.ILSpy.ReadyToRun
[Export(typeof(Language))] [Export(typeof(Language))]
[Shared] [Shared]
internal class ReadyToRunLanguage : Language internal class ReadyToRunLanguage(SettingsService settingsService, IExportProvider exportProvider) : Language
{ {
private static readonly ConditionalWeakTable<MetadataFile, ReadyToRunReaderCacheEntry> readyToRunReaders = new ConditionalWeakTable<MetadataFile, ReadyToRunReaderCacheEntry>(); private static readonly ConditionalWeakTable<MetadataFile, ReadyToRunReaderCacheEntry> readyToRunReaders = new ConditionalWeakTable<MetadataFile, ReadyToRunReaderCacheEntry>();
@ -175,7 +179,7 @@ namespace ICSharpCode.ILSpy.ReadyToRun
.GroupBy(m => m.MethodHandle) .GroupBy(m => m.MethodHandle)
.ToDictionary(g => g.Key, g => g.ToArray()); .ToDictionary(g => g.Key, g => g.ToArray());
} }
var displaySettings = SettingsService.Instance.DisplaySettings; var displaySettings = settingsService.DisplaySettings;
bool showMetadataTokens = displaySettings.ShowMetadataTokens; bool showMetadataTokens = displaySettings.ShowMetadataTokens;
bool showMetadataTokensInBase10 = displaySettings.ShowMetadataTokensInBase10; bool showMetadataTokensInBase10 = displaySettings.ShowMetadataTokensInBase10;
#if STRESS #if STRESS
@ -205,7 +209,7 @@ namespace ICSharpCode.ILSpy.ReadyToRun
file = ((IlSpyAssemblyMetadata)readyToRunMethod.ComponentReader).Module; file = ((IlSpyAssemblyMetadata)readyToRunMethod.ComponentReader).Module;
} }
new ReadyToRunDisassembler(output, disassemblingReader, runtimeFunction).Disassemble(file, bitness, (ulong)runtimeFunction.StartAddress, showMetadataTokens, showMetadataTokensInBase10); new ReadyToRunDisassembler(output, disassemblingReader, runtimeFunction, settingsService).Disassemble(file, bitness, (ulong)runtimeFunction.StartAddress, showMetadataTokens, showMetadataTokensInBase10);
} }
} }
} }
@ -218,7 +222,7 @@ namespace ICSharpCode.ILSpy.ReadyToRun
public override RichText GetRichTextTooltip(IEntity entity) public override RichText GetRichTextTooltip(IEntity entity)
{ {
return LanguageService.Instance.ILLanguage.GetRichTextTooltip(entity); return exportProvider.GetExportedValue<LanguageService>().ILLanguage.GetRichTextTooltip(entity);
} }
private ReadyToRunReaderCacheEntry GetReader(LoadedAssembly assembly, MetadataFile file) private ReadyToRunReaderCacheEntry GetReader(LoadedAssembly assembly, MetadataFile file)

2
ILSpy.Tests/Analyzers/MemberImplementsInterfaceAnalyzerTests.cs

@ -145,7 +145,7 @@ namespace ICSharpCode.ILSpy.Tests.Analyzers
var analyzer = new MemberImplementsInterfaceAnalyzer(); var analyzer = new MemberImplementsInterfaceAnalyzer();
// Act // Act
var results = analyzer.Analyze(symbol, new AnalyzerContext() { AssemblyList = new ILSpyX.AssemblyList(), Language = new CSharpLanguage([]) }); var results = analyzer.Analyze(symbol, new AnalyzerContext() { AssemblyList = new ILSpyX.AssemblyList(), Language = new CSharpLanguage() });
// Assert // Assert
Assert.That(results, Is.Not.Null); Assert.That(results, Is.Not.Null);

2
ILSpy.Tests/Analyzers/MethodUsesAnalyzerTests.cs

@ -30,7 +30,7 @@ namespace ICSharpCode.ILSpy.Tests.Analyzers
testAssembly = assemblyList.OpenAssembly(typeof(MethodUsesAnalyzerTests).Assembly.Location); testAssembly = assemblyList.OpenAssembly(typeof(MethodUsesAnalyzerTests).Assembly.Location);
assemblyList.OpenAssembly(typeof(void).Assembly.Location); assemblyList.OpenAssembly(typeof(void).Assembly.Location);
testAssemblyTypeSystem = testAssembly.GetTypeSystemOrNull(); testAssemblyTypeSystem = testAssembly.GetTypeSystemOrNull();
language = new CSharpLanguage([]); language = new CSharpLanguage();
typeDefinition = testAssemblyTypeSystem.FindType(typeof(TestCases.Main.MainAssembly)).GetDefinition(); typeDefinition = testAssemblyTypeSystem.FindType(typeof(TestCases.Main.MainAssembly)).GetDefinition();
} }

2
ILSpy.Tests/Analyzers/TypeUsedByAnalyzerTests.cs

@ -41,7 +41,7 @@ namespace ICSharpCode.ILSpy.Tests.Analyzers
assemblyList = new AssemblyList(); assemblyList = new AssemblyList();
testAssembly = assemblyList.OpenAssembly(typeof(MethodUsesAnalyzerTests).Assembly.Location); testAssembly = assemblyList.OpenAssembly(typeof(MethodUsesAnalyzerTests).Assembly.Location);
testAssemblyTypeSystem = new DecompilerTypeSystem(testAssembly.GetMetadataFileOrNull(), testAssembly.GetAssemblyResolver()); testAssemblyTypeSystem = new DecompilerTypeSystem(testAssembly.GetMetadataFileOrNull(), testAssembly.GetAssemblyResolver());
language = new CSharpLanguage([]); language = new CSharpLanguage();
} }
[Test] [Test]

15
ILSpy/AboutPage.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using System.Composition; using System.Composition;
using System.IO; using System.IO;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -28,6 +29,7 @@ using System.Windows.Navigation;
using ICSharpCode.AvalonEdit.Rendering; using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.Themes; using ICSharpCode.ILSpy.Themes;
@ -38,17 +40,22 @@ namespace ICSharpCode.ILSpy
{ {
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._Help), Header = nameof(Resources._About), MenuOrder = 99999)] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._Help), Header = nameof(Resources._About), MenuOrder = 99999)]
[Shared] [Shared]
sealed class AboutPage : SimpleCommand public sealed class AboutPageCommand(AssemblyTreeModel assemblyTreeModel) : SimpleCommand
{ {
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
MainWindow.Instance.AssemblyTreeModel.NavigateTo( assemblyTreeModel.NavigateTo(
new RequestNavigateEventArgs(new Uri("resource://aboutpage"), null), new RequestNavigateEventArgs(new Uri("resource://aboutpage"), null),
inNewTabPage: true inNewTabPage: true
); );
} }
}
public static void Display(DecompilerTextView textView) [Export]
[Shared]
public sealed class AboutPage(IEnumerable<IAboutPageAddition> aboutPageAdditions)
{
public void Display(DecompilerTextView textView)
{ {
AvalonEditTextOutput output = new AvalonEditTextOutput() { AvalonEditTextOutput output = new AvalonEditTextOutput() {
Title = Resources.About, Title = Resources.About,
@ -86,7 +93,7 @@ namespace ICSharpCode.ILSpy
}); });
output.WriteLine(); output.WriteLine();
foreach (var plugin in App.ExportProvider.GetExportedValues<IAboutPageAddition>()) foreach (var plugin in aboutPageAdditions)
plugin.Write(output); plugin.Write(output);
output.WriteLine(); output.WriteLine();
output.Address = new Uri("resource://AboutPage"); output.Address = new Uri("resource://AboutPage");

21
ILSpy/Analyzers/AnalyzeCommand.cs

@ -20,17 +20,18 @@ using System.Composition;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
using TomsToolbox.Composition;
namespace ICSharpCode.ILSpy.Analyzers namespace ICSharpCode.ILSpy.Analyzers
{ {
[ExportContextMenuEntry(Header = nameof(Resources.Analyze), Icon = "Images/Search", Category = nameof(Resources.Analyze), InputGestureText = "Ctrl+R", Order = 100)] [ExportContextMenuEntry(Header = nameof(Resources.Analyze), Icon = "Images/Search", Category = nameof(Resources.Analyze), InputGestureText = "Ctrl+R", Order = 100)]
[Shared] [Shared]
internal sealed class AnalyzeContextMenuCommand : IContextMenuEntry internal sealed class AnalyzeContextMenuCommand(AnalyzerTreeViewModel analyzerTreeView) : IContextMenuEntry
{ {
private static readonly AnalyzerTreeViewModel AnalyzerTreeView = App.ExportProvider.GetExportedValue<AnalyzerTreeViewModel>();
public bool IsVisible(TextViewContext context) public bool IsVisible(TextViewContext context)
{ {
if (context.TreeView is AnalyzerTreeView && context.SelectedTreeNodes != null && context.SelectedTreeNodes.All(n => n.Parent.IsRoot)) if (context.TreeView is AnalyzerTreeView && context.SelectedTreeNodes != null && context.SelectedTreeNodes.All(n => n.Parent.IsRoot))
@ -62,30 +63,28 @@ namespace ICSharpCode.ILSpy.Analyzers
{ {
foreach (var node in context.SelectedTreeNodes.OfType<IMemberTreeNode>().ToArray()) foreach (var node in context.SelectedTreeNodes.OfType<IMemberTreeNode>().ToArray())
{ {
AnalyzerTreeView.Analyze(node.Member); analyzerTreeView.Analyze(node.Member);
} }
} }
else if (context.Reference is { Reference: IEntity entity }) else if (context.Reference is { Reference: IEntity entity })
{ {
AnalyzerTreeView.Analyze(entity); analyzerTreeView.Analyze(entity);
} }
} }
} }
internal sealed class AnalyzeCommand : SimpleCommand public sealed class AnalyzeCommand(AssemblyTreeModel assemblyTreeModel, AnalyzerTreeViewModel analyzerTreeViewModel) : SimpleCommand
{ {
private static readonly AnalyzerTreeViewModel AnalyzerTreeView = App.ExportProvider.GetExportedValue<AnalyzerTreeViewModel>();
public override bool CanExecute(object parameter) public override bool CanExecute(object parameter)
{ {
return MainWindow.Instance.AssemblyTreeModel.SelectedNodes.All(n => n is IMemberTreeNode); return assemblyTreeModel.SelectedNodes.All(n => n is IMemberTreeNode);
} }
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
foreach (var node in MainWindow.Instance.AssemblyTreeModel.SelectedNodes.OfType<IMemberTreeNode>()) foreach (var node in assemblyTreeModel.SelectedNodes.OfType<IMemberTreeNode>())
{ {
AnalyzerTreeView.Analyze(node.Member); analyzerTreeViewModel.Analyze(node.Member);
} }
} }
} }

2
ILSpy/Analyzers/AnalyzerSearchTreeNode.cs

@ -61,7 +61,7 @@ namespace ICSharpCode.ILSpy.Analyzers
var context = new AnalyzerContext() { var context = new AnalyzerContext() {
CancellationToken = ct, CancellationToken = ct,
Language = Language, Language = Language,
AssemblyList = MainWindow.Instance.AssemblyTreeModel.AssemblyList AssemblyList = AssemblyTreeModel.AssemblyList
}; };
var results = analyzer.Analyze(symbol, context).Select(SymbolTreeNodeFactory); var results = analyzer.Analyze(symbol, context).Select(SymbolTreeNodeFactory);
if (context.SortResults) if (context.SortResults)

14
ILSpy/Analyzers/AnalyzerTreeNode.cs

@ -17,15 +17,20 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpyX.Analyzers;
using ICSharpCode.ILSpyX.TreeView; using ICSharpCode.ILSpyX.TreeView;
using TomsToolbox.Composition;
namespace ICSharpCode.ILSpy.Analyzers namespace ICSharpCode.ILSpy.Analyzers
{ {
public abstract class AnalyzerTreeNode : SharpTreeNode public abstract class AnalyzerTreeNode : SharpTreeNode
{ {
public Language Language => LanguageService.Instance.Language; public static Language Language => App.ExportProvider.GetExportedValue<LanguageService>().Language;
public override bool CanDelete() public override bool CanDelete()
{ {
@ -42,6 +47,13 @@ namespace ICSharpCode.ILSpy.Analyzers
DeleteCore(); DeleteCore();
} }
public static AssemblyTreeModel AssemblyTreeModel { get; } = App.ExportProvider.GetExportedValue<AssemblyTreeModel>();
public static ICollection<IExport<IAnalyzer, IAnalyzerMetadata>> Analyzers => App.ExportProvider
.GetExports<IAnalyzer, IAnalyzerMetadata>("Analyzer")
.OrderBy(item => item.Metadata?.Order)
.ToArray();
/// <summary> /// <summary>
/// Handles changes to the assembly list. /// Handles changes to the assembly list.
/// </summary> /// </summary>

5
ILSpy/Analyzers/AnalyzerTreeViewModel.cs

@ -24,6 +24,7 @@ using System.Windows.Input;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.Analyzers.TreeNodes; using ICSharpCode.ILSpy.Analyzers.TreeNodes;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpy.ViewModels;
@ -38,12 +39,12 @@ namespace ICSharpCode.ILSpy.Analyzers
{ {
public const string PaneContentId = "analyzerPane"; public const string PaneContentId = "analyzerPane";
public AnalyzerTreeViewModel() public AnalyzerTreeViewModel(AssemblyTreeModel assemblyTreeModel)
{ {
ContentId = PaneContentId; ContentId = PaneContentId;
Title = Properties.Resources.Analyze; Title = Properties.Resources.Analyze;
ShortcutKey = new(Key.R, ModifierKeys.Control); ShortcutKey = new(Key.R, ModifierKeys.Control);
AssociatedCommand = ILSpyCommands.Analyze; AssociatedCommand = new AnalyzeCommand(assemblyTreeModel, this);
} }
public AnalyzerRootNode Root { get; } = new(); public AnalyzerRootNode Root { get; } = new();

15
ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs

@ -17,15 +17,12 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
namespace ICSharpCode.ILSpy.Analyzers.TreeNodes namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
{ {
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpyX.Analyzers;
internal sealed class AnalyzedEventTreeNode : AnalyzerEntityTreeNode internal sealed class AnalyzedEventTreeNode : AnalyzerEntityTreeNode
{ {
readonly IEvent analyzedEvent; readonly IEvent analyzedEvent;
@ -54,16 +51,12 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
if (TryFindBackingField(analyzedEvent, out var backingField)) if (TryFindBackingField(analyzedEvent, out var backingField))
this.Children.Add(new AnalyzedFieldTreeNode(backingField)); this.Children.Add(new AnalyzedFieldTreeNode(backingField));
//foreach (var accessor in analyzedEvent.OtherMethods) foreach (var lazy in Analyzers)
// this.Children.Add(new AnalyzedAccessorTreeNode(accessor, null));
var analyzers = App.ExportProvider.GetExports<IAnalyzer, IAnalyzerMetadata>("Analyzer");
foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order))
{ {
var analyzer = lazy.Value; var analyzer = lazy.Value;
if (analyzer.Show(analyzedEvent)) if (analyzer.Show(analyzedEvent))
{ {
this.Children.Add(new AnalyzerSearchTreeNode(analyzedEvent, analyzer, lazy.Metadata.Header)); this.Children.Add(new AnalyzerSearchTreeNode(analyzedEvent, analyzer, lazy.Metadata?.Header));
} }
} }
} }
@ -73,7 +66,7 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
backingField = null; backingField = null;
foreach (var field in analyzedEvent.DeclaringTypeDefinition.GetFields(options: GetMemberOptions.IgnoreInheritedMembers)) foreach (var field in analyzedEvent.DeclaringTypeDefinition.GetFields(options: GetMemberOptions.IgnoreInheritedMembers))
{ {
if (field.Name == analyzedEvent.Name && field.Accessibility == Accessibility.Private) if (field.Name == analyzedEvent.Name && field.Accessibility == Decompiler.TypeSystem.Accessibility.Private)
{ {
backingField = field; backingField = field;
return true; return true;

7
ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs

@ -17,11 +17,9 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpyX.Analyzers;
namespace ICSharpCode.ILSpy.Analyzers.TreeNodes namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
{ {
@ -41,13 +39,12 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
protected override void LoadChildren() protected override void LoadChildren()
{ {
var analyzers = App.ExportProvider.GetExports<IAnalyzer, IAnalyzerMetadata>("Analyzer"); foreach (var lazy in Analyzers)
foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order))
{ {
var analyzer = lazy.Value; var analyzer = lazy.Value;
if (analyzer.Show(analyzedField)) if (analyzer.Show(analyzedField))
{ {
this.Children.Add(new AnalyzerSearchTreeNode(analyzedField, analyzer, lazy.Metadata.Header)); this.Children.Add(new AnalyzerSearchTreeNode(analyzedField, analyzer, lazy.Metadata?.Header));
} }
} }
} }

5
ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs

@ -17,11 +17,9 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpyX.Analyzers;
namespace ICSharpCode.ILSpy.Analyzers.TreeNodes namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
{ {
@ -43,8 +41,7 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
protected override void LoadChildren() protected override void LoadChildren()
{ {
var analyzers = App.ExportProvider.GetExports<IAnalyzer, IAnalyzerMetadata>("Analyzer"); foreach (var lazy in Analyzers)
foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order))
{ {
var analyzer = lazy.Value; var analyzer = lazy.Value;
if (analyzer.Show(analyzedMethod)) if (analyzer.Show(analyzedMethod))

5
ILSpy/Analyzers/TreeNodes/AnalyzedModuleTreeNode.cs

@ -17,11 +17,9 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Linq;
using System.Windows; using System.Windows;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpyX.Analyzers;
using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions; using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions;
namespace ICSharpCode.ILSpy.Analyzers.TreeNodes namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
@ -42,8 +40,7 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
protected override void LoadChildren() protected override void LoadChildren()
{ {
var analyzers = App.ExportProvider.GetExports<IAnalyzer, IAnalyzerMetadata>("Analyzer"); foreach (var lazy in Analyzers)
foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order))
{ {
var analyzer = lazy.Value; var analyzer = lazy.Value;
if (analyzer.Show(analyzedModule)) if (analyzer.Show(analyzedModule))

7
ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs

@ -17,11 +17,9 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpyX.Analyzers;
namespace ICSharpCode.ILSpy.Analyzers.TreeNodes namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
{ {
@ -48,11 +46,8 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
this.Children.Add(new AnalyzedAccessorTreeNode(analyzedProperty.Getter, "get")); this.Children.Add(new AnalyzedAccessorTreeNode(analyzedProperty.Getter, "get"));
if (analyzedProperty.CanSet) if (analyzedProperty.CanSet)
this.Children.Add(new AnalyzedAccessorTreeNode(analyzedProperty.Setter, "set")); this.Children.Add(new AnalyzedAccessorTreeNode(analyzedProperty.Setter, "set"));
//foreach (var accessor in analyzedProperty.OtherMethods)
// this.Children.Add(new AnalyzedPropertyAccessorTreeNode(accessor, null));
var analyzers = App.ExportProvider.GetExports<IAnalyzer, IAnalyzerMetadata>("Analyzer"); foreach (var lazy in Analyzers)
foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order))
{ {
var analyzer = lazy.Value; var analyzer = lazy.Value;
if (analyzer.Show(analyzedProperty)) if (analyzer.Show(analyzedProperty))

5
ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs

@ -17,11 +17,9 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpyX.Analyzers;
namespace ICSharpCode.ILSpy.Analyzers.TreeNodes namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
{ {
@ -41,8 +39,7 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
protected override void LoadChildren() protected override void LoadChildren()
{ {
var analyzers = App.ExportProvider.GetExports<IAnalyzer, IAnalyzerMetadata>("Analyzer"); foreach (var lazy in Analyzers)
foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order))
{ {
var analyzer = lazy.Value; var analyzer = lazy.Value;
if (analyzer.Show(analyzedType)) if (analyzer.Show(analyzedType))

16
ILSpy/App.xaml.cs

@ -71,8 +71,10 @@ namespace ICSharpCode.ILSpy
var cmdArgs = Environment.GetCommandLineArgs().Skip(1); var cmdArgs = Environment.GetCommandLineArgs().Skip(1);
CommandLineArguments = CommandLineArguments.Create(cmdArgs); CommandLineArguments = CommandLineArguments.Create(cmdArgs);
var settingsService = new SettingsService();
bool forceSingleInstance = (CommandLineArguments.SingleInstance ?? true) bool forceSingleInstance = (CommandLineArguments.SingleInstance ?? true)
&& !SettingsService.Instance.MiscSettings.AllowMultipleInstances; && !settingsService.MiscSettings.AllowMultipleInstances;
if (forceSingleInstance) if (forceSingleInstance)
{ {
SingleInstance.Attach(); // will auto-exit for second instance SingleInstance.Attach(); // will auto-exit for second instance
@ -81,7 +83,7 @@ namespace ICSharpCode.ILSpy
InitializeComponent(); InitializeComponent();
if (!InitializeDependencyInjection(SettingsService.Instance)) if (!InitializeDependencyInjection(settingsService))
{ {
// There is something completely wrong with DI, probably some service registration is missing => nothing we can do to recover, so stop and shut down. // There is something completely wrong with DI, probably some service registration is missing => nothing we can do to recover, so stop and shut down.
Exit += (_, _) => MessageBox.Show(StartupExceptions.FormatExceptions(), "Sorry we crashed!"); Exit += (_, _) => MessageBox.Show(StartupExceptions.FormatExceptions(), "Sorry we crashed!");
@ -106,7 +108,7 @@ namespace ICSharpCode.ILSpy
// Add data templates registered via MEF. // Add data templates registered via MEF.
Resources.MergedDictionaries.Add(DataTemplateManager.CreateDynamicDataTemplates(ExportProvider)); Resources.MergedDictionaries.Add(DataTemplateManager.CreateDynamicDataTemplates(ExportProvider));
var sessionSettings = SettingsService.Instance.SessionSettings; var sessionSettings = settingsService.SessionSettings;
ThemeManager.Current.Theme = sessionSettings.Theme; ThemeManager.Current.Theme = sessionSettings.Theme;
if (!string.IsNullOrEmpty(sessionSettings.CurrentCulture)) if (!string.IsNullOrEmpty(sessionSettings.CurrentCulture))
{ {
@ -129,7 +131,7 @@ namespace ICSharpCode.ILSpy
MessageBox.Show(unknownArguments, "ILSpy Unknown Command Line Arguments Passed"); MessageBox.Show(unknownArguments, "ILSpy Unknown Command Line Arguments Passed");
} }
SettingsService.Instance.AssemblyListManager.CreateDefaultAssemblyLists(); settingsService.AssemblyListManager.CreateDefaultAssemblyLists();
} }
public new static App Current => (App)Application.Current; public new static App Current => (App)Application.Current;
@ -187,6 +189,10 @@ namespace ICSharpCode.ILSpy
services.BindExports(Assembly.GetExecutingAssembly()); services.BindExports(Assembly.GetExecutingAssembly());
// Add the settings service // Add the settings service
services.AddSingleton(settingsService); services.AddSingleton(settingsService);
// Add the export provider
services.AddSingleton(_ => ExportProvider);
// Add the docking manager
services.AddSingleton(serviceProvider => serviceProvider.GetService<MainWindow>().DockManager);
var serviceProvider = services.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true }); var serviceProvider = services.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true });
@ -209,7 +215,7 @@ namespace ICSharpCode.ILSpy
{ {
base.OnStartup(e); base.OnStartup(e);
MainWindow = new(); MainWindow = ExportProvider.GetExportedValue<MainWindow>();
MainWindow.Show(); MainWindow.Show();
} }

53
ILSpy/AssemblyTree/AssemblyTreeModel.cs

@ -47,6 +47,7 @@ using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpyX.Settings; using ICSharpCode.ILSpyX.Settings;
using ICSharpCode.ILSpyX.TreeView; using ICSharpCode.ILSpyX.TreeView;
using TomsToolbox.Composition;
using TomsToolbox.Essentials; using TomsToolbox.Essentials;
using TomsToolbox.Wpf; using TomsToolbox.Wpf;
@ -67,9 +68,20 @@ namespace ICSharpCode.ILSpy.AssemblyTree
private readonly NavigationHistory<NavigationState> history = new(); private readonly NavigationHistory<NavigationState> history = new();
private bool isNavigatingHistory; private bool isNavigatingHistory;
private readonly AboutPage aboutPage;
private readonly SearchPaneModel searchPaneModel;
private readonly SettingsService settingsService;
private readonly LanguageService languageService;
private readonly IExportProvider exportProvider;
public AssemblyTreeModel() public AssemblyTreeModel(AboutPage aboutPage, SearchPaneModel searchPaneModel, SettingsService settingsService, LanguageService languageService, IExportProvider exportProvider)
{ {
this.aboutPage = aboutPage;
this.searchPaneModel = searchPaneModel;
this.settingsService = settingsService;
this.languageService = languageService;
this.exportProvider = exportProvider;
Title = Resources.Assemblies; Title = Resources.Assemblies;
ContentId = PaneContentId; ContentId = PaneContentId;
IsCloseable = false; IsCloseable = false;
@ -80,7 +92,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
refreshThrottle = new DispatcherThrottle(DispatcherPriority.Background, RefreshInternal); refreshThrottle = new DispatcherThrottle(DispatcherPriority.Background, RefreshInternal);
AssemblyList = SettingsService.Instance.CreateEmptyAssemblyList(); AssemblyList = settingsService.CreateEmptyAssemblyList();
} }
private void Settings_PropertyChanged(object? sender, PropertyChangedEventArgs e) private void Settings_PropertyChanged(object? sender, PropertyChangedEventArgs e)
@ -151,7 +163,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
{ {
LoadAssemblies(args.AssembliesToLoad, commandLineLoadedAssemblies, focusNode: false); LoadAssemblies(args.AssembliesToLoad, commandLineLoadedAssemblies, focusNode: false);
if (args.Language != null) if (args.Language != null)
LanguageService.Instance.Language = LanguageService.Instance.GetLanguage(args.Language); languageService.Language = languageService.GetLanguage(args.Language);
return true; return true;
} }
@ -161,7 +173,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
/// </summary> /// </summary>
private async Task HandleCommandLineArgumentsAfterShowList(CommandLineArguments args, ISettingsProvider? spySettings = null) private async Task HandleCommandLineArgumentsAfterShowList(CommandLineArguments args, ISettingsProvider? spySettings = null)
{ {
var sessionSettings = SettingsService.Instance.SessionSettings; var sessionSettings = settingsService.SessionSettings;
var relevantAssemblies = commandLineLoadedAssemblies.ToList(); var relevantAssemblies = commandLineLoadedAssemblies.ToList();
commandLineLoadedAssemblies.Clear(); // clear references once we don't need them anymore commandLineLoadedAssemblies.Clear(); // clear references once we don't need them anymore
@ -170,10 +182,8 @@ namespace ICSharpCode.ILSpy.AssemblyTree
if (args.Search != null) if (args.Search != null)
{ {
var searchPane = App.ExportProvider.GetExportedValue<SearchPaneModel>(); this.searchPaneModel.SearchTerm = args.Search;
this.searchPaneModel.Show();
searchPane.SearchTerm = args.Search;
searchPane.Show();
} }
} }
@ -290,11 +300,11 @@ namespace ICSharpCode.ILSpy.AssemblyTree
SelectNode(node); SelectNode(node);
// only if not showing the about page, perform the update check: // only if not showing the about page, perform the update check:
await MainWindow.Instance.ShowMessageIfUpdatesAvailableAsync(spySettings); await App.Current.MainWindow.ShowMessageIfUpdatesAvailableAsync(spySettings);
} }
else else
{ {
DockWorkspace.Instance.ActiveTabPage.ShowTextView(AboutPage.Display); DockWorkspace.Instance.ActiveTabPage.ShowTextView(aboutPage.Display);
} }
} }
} }
@ -363,11 +373,11 @@ namespace ICSharpCode.ILSpy.AssemblyTree
public void Initialize() public void Initialize()
{ {
AssemblyList = SettingsService.Instance.LoadInitialAssemblyList(); AssemblyList = settingsService.LoadInitialAssemblyList();
HandleCommandLineArguments(App.CommandLineArguments); HandleCommandLineArguments(App.CommandLineArguments);
var loadPreviousAssemblies = SettingsService.Instance.MiscSettings.LoadPreviousAssemblies; var loadPreviousAssemblies = settingsService.MiscSettings.LoadPreviousAssemblies;
if (AssemblyList.GetAssemblies().Length == 0 if (AssemblyList.GetAssemblies().Length == 0
&& AssemblyList.ListName == AssemblyListManager.DefaultListName && AssemblyList.ListName == AssemblyListManager.DefaultListName
&& loadPreviousAssemblies) && loadPreviousAssemblies)
@ -377,7 +387,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
ShowAssemblyList(AssemblyList); ShowAssemblyList(AssemblyList);
var sessionSettings = SettingsService.Instance.SessionSettings; var sessionSettings = settingsService.SessionSettings;
if (sessionSettings.ActiveAutoLoadedAssembly != null if (sessionSettings.ActiveAutoLoadedAssembly != null
&& File.Exists(sessionSettings.ActiveAutoLoadedAssembly)) && File.Exists(sessionSettings.ActiveAutoLoadedAssembly))
{ {
@ -389,7 +399,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
private async Task OpenAssemblies() private async Task OpenAssemblies()
{ {
await HandleCommandLineArgumentsAfterShowList(App.CommandLineArguments, SettingsService.Instance.SpySettings); await HandleCommandLineArgumentsAfterShowList(App.CommandLineArguments, settingsService.SpySettings);
if (FormatExceptions(App.StartupExceptions.ToArray(), out var output)) if (FormatExceptions(App.StartupExceptions.ToArray(), out var output))
{ {
@ -416,7 +426,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
private void ShowAssemblyList(string name) private void ShowAssemblyList(string name)
{ {
AssemblyList list = SettingsService.Instance.AssemblyListManager.LoadList(name); AssemblyList list = settingsService.AssemblyListManager.LoadList(name);
//Only load a new list when it is a different one //Only load a new list when it is a different one
if (list.ListName != AssemblyList.ListName) if (list.ListName != AssemblyList.ListName)
{ {
@ -655,8 +665,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
} }
if (protocol != "decompile") if (protocol != "decompile")
{ {
var protocolHandlers = App.ExportProvider.GetExportedValues<IProtocolHandler>(); foreach (var handler in exportProvider.GetExportedValues<IProtocolHandler>())
foreach (var handler in protocolHandlers)
{ {
var node = handler.Resolve(protocol, file, unresolvedEntity.Handle, out bool newTabPage); var node = handler.Resolve(protocol, file, unresolvedEntity.Handle, out bool newTabPage);
if (node != null) if (node != null)
@ -793,7 +802,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
return; return;
} }
var options = LanguageService.Instance.CreateDecompilationOptions(activeTabPage); var options = activeTabPage.CreateDecompilationOptions();
options.TextViewState = newState; options.TextViewState = newState;
activeTabPage.ShowTextViewAsync(textView => textView.DecompileAsync(this.CurrentLanguage, this.SelectedNodes, options)); activeTabPage.ShowTextViewAsync(textView => textView.DecompileAsync(this.CurrentLanguage, this.SelectedNodes, options));
} }
@ -803,9 +812,9 @@ namespace ICSharpCode.ILSpy.AssemblyTree
DecompileSelectedNodes(DockWorkspace.Instance.ActiveTabPage.GetState() as DecompilerTextViewState); DecompileSelectedNodes(DockWorkspace.Instance.ActiveTabPage.GetState() as DecompilerTextViewState);
} }
public Language CurrentLanguage => LanguageService.Instance.Language; public Language CurrentLanguage => languageService.Language;
public LanguageVersion? CurrentLanguageVersion => LanguageService.Instance.LanguageVersion; public LanguageVersion? CurrentLanguageVersion => languageService.LanguageVersion;
public IEnumerable<ILSpyTreeNode> SelectedNodes { public IEnumerable<ILSpyTreeNode> SelectedNodes {
get { get {
@ -858,7 +867,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
if (e.Uri.Host == "aboutpage") if (e.Uri.Host == "aboutpage")
{ {
RecordHistory(); RecordHistory();
DockWorkspace.Instance.ActiveTabPage.ShowTextView(AboutPage.Display); DockWorkspace.Instance.ActiveTabPage.ShowTextView(aboutPage.Display);
e.Handled = true; e.Handled = true;
return; return;
} }
@ -912,7 +921,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
{ {
var path = GetPathForNode(SelectedItem); var path = GetPathForNode(SelectedItem);
ShowAssemblyList(SettingsService.Instance.AssemblyListManager.LoadList(AssemblyList.ListName)); ShowAssemblyList(settingsService.AssemblyListManager.LoadList(AssemblyList.ListName));
SelectNode(FindNodeByPath(path, true), inNewTabPage: false); SelectNode(FindNodeByPath(path, true), inNewTabPage: false);
RefreshDecompiledView(); RefreshDecompiledView();

9
ILSpy/Commands/CheckForUpdatesCommand.cs

@ -25,16 +25,11 @@ namespace ICSharpCode.ILSpy
{ {
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._Help), Header = nameof(Resources._CheckUpdates), MenuOrder = 5000)] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._Help), Header = nameof(Resources._CheckUpdates), MenuOrder = 5000)]
[Shared] [Shared]
sealed class CheckForUpdatesCommand : SimpleCommand sealed class CheckForUpdatesCommand(SettingsService settingsService) : SimpleCommand
{ {
public override bool CanExecute(object parameter)
{
return base.CanExecute(parameter);
}
public override async void Execute(object parameter) public override async void Execute(object parameter)
{ {
await MainWindow.Instance.ShowMessageIfUpdatesAvailableAsync(SettingsService.Instance.SpySettings, forceCheck: true); await App.Current.MainWindow.ShowMessageIfUpdatesAvailableAsync(settingsService.SpySettings, forceCheck: true);
} }
} }
} }

25
ILSpy/Commands/DecompileAllCommand.cs

@ -27,24 +27,19 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDecompile), MenuCategory = nameof(Resources.Open), MenuOrder = 2.5)] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDecompile), MenuCategory = nameof(Resources.Open), MenuOrder = 2.5)]
[Shared] [Shared]
sealed class DecompileAllCommand : SimpleCommand sealed class DecompileAllCommand(AssemblyTreeModel assemblyTreeModel, LanguageService languageService) : SimpleCommand
{ {
private readonly IReadOnlyCollection<IResourceFileHandler> resourceFileHandlers;
public DecompileAllCommand(IEnumerable<IResourceFileHandler> resourceFileHandlers)
{
this.resourceFileHandlers = resourceFileHandlers.ToArray();
}
public override bool CanExecute(object parameter) public override bool CanExecute(object parameter)
{ {
return System.IO.Directory.Exists("c:\\temp\\decompiled"); return System.IO.Directory.Exists("c:\\temp\\decompiled");
@ -55,7 +50,7 @@ namespace ICSharpCode.ILSpy
Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => { Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
AvalonEditTextOutput output = new AvalonEditTextOutput(); AvalonEditTextOutput output = new AvalonEditTextOutput();
Parallel.ForEach( Parallel.ForEach(
Partitioner.Create(MainWindow.Instance.AssemblyTreeModel.AssemblyList.GetAssemblies(), loadBalance: true), Partitioner.Create(assemblyTreeModel.AssemblyList.GetAssemblies(), loadBalance: true),
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct }, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct },
delegate (LoadedAssembly asm) { delegate (LoadedAssembly asm) {
if (!asm.HasLoadError) if (!asm.HasLoadError)
@ -66,10 +61,10 @@ namespace ICSharpCode.ILSpy
{ {
try try
{ {
var options = LanguageService.Instance.CreateDecompilationOptions(DockWorkspace.Instance.ActiveTabPage); var options = DockWorkspace.Instance.ActiveTabPage.CreateDecompilationOptions();
options.CancellationToken = ct; options.CancellationToken = ct;
options.FullDecompilation = true; options.FullDecompilation = true;
new CSharpLanguage(resourceFileHandlers).DecompileAssembly(asm, new PlainTextOutput(writer), options); new CSharpLanguage().DecompileAssembly(asm, new PlainTextOutput(writer), options);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -96,15 +91,15 @@ namespace ICSharpCode.ILSpy
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDecompile100x), MenuCategory = nameof(Resources.Open), MenuOrder = 2.6)] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDecompile100x), MenuCategory = nameof(Resources.Open), MenuOrder = 2.6)]
[Shared] [Shared]
sealed class Decompile100TimesCommand : SimpleCommand sealed class Decompile100TimesCommand(AssemblyTreeModel assemblyTreeModel, LanguageService languageService) : SimpleCommand
{ {
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
const int numRuns = 100; const int numRuns = 100;
var language = LanguageService.Instance.Language; var language = languageService.Language;
var nodes = MainWindow.Instance.AssemblyTreeModel.SelectedNodes.ToArray(); var nodes = assemblyTreeModel.SelectedNodes.ToArray();
DockWorkspace dockWorkspace = DockWorkspace.Instance; DockWorkspace dockWorkspace = DockWorkspace.Instance;
var options = LanguageService.Instance.CreateDecompilationOptions(dockWorkspace.ActiveTabPage); var options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions();
dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => { dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
options.CancellationToken = ct; options.CancellationToken = ct;
Stopwatch w = Stopwatch.StartNew(); Stopwatch w = Stopwatch.StartNew();

8
ILSpy/Commands/DisassembleAllCommand.cs

@ -24,14 +24,16 @@ using System.Composition;
using System.Diagnostics; using System.Diagnostics;
using System.Threading.Tasks; using System.Threading.Tasks;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDisassemble), MenuCategory = nameof(Resources.Open), MenuOrder = 2.5)] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDisassemble), MenuCategory = nameof(Resources.Open), MenuOrder = 2.5)]
[Shared] [Shared]
sealed class DisassembleAllCommand : SimpleCommand sealed class DisassembleAllCommand(AssemblyTreeModel assemblyTreeModel, LanguageService languageService) : SimpleCommand
{ {
public override bool CanExecute(object parameter) public override bool CanExecute(object parameter)
{ {
@ -45,7 +47,7 @@ namespace ICSharpCode.ILSpy
dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => { dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
AvalonEditTextOutput output = new(); AvalonEditTextOutput output = new();
Parallel.ForEach( Parallel.ForEach(
Partitioner.Create(MainWindow.Instance.AssemblyTreeModel.AssemblyList.GetAssemblies(), loadBalance: true), Partitioner.Create(assemblyTreeModel.AssemblyList.GetAssemblies(), loadBalance: true),
new() { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct }, new() { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct },
asm => { asm => {
if (!asm.HasLoadError) if (!asm.HasLoadError)
@ -56,7 +58,7 @@ namespace ICSharpCode.ILSpy
{ {
try try
{ {
var options = LanguageService.Instance.CreateDecompilationOptions(dockWorkspace.ActiveTabPage); var options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions();
options.FullDecompilation = true; options.FullDecompilation = true;
options.CancellationToken = ct; options.CancellationToken = ct;
new ILLanguage().DecompileAssembly(asm, new Decompiler.PlainTextOutput(writer), options); new ILLanguage().DecompileAssembly(asm, new Decompiler.PlainTextOutput(writer), options);

2
ILSpy/Commands/ExitCommand.cs

@ -27,7 +27,7 @@ namespace ICSharpCode.ILSpy
{ {
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
MainWindow.Instance.Close(); App.Current.MainWindow.Close();
} }
} }
} }

20
ILSpy/Commands/GeneratePdbContextMenuEntry.cs

@ -29,10 +29,12 @@ using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler; using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
using ICSharpCode.Decompiler.DebugInfo; using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
using Microsoft.Win32; using Microsoft.Win32;
@ -41,14 +43,14 @@ namespace ICSharpCode.ILSpy
{ {
[ExportContextMenuEntry(Header = nameof(Resources.GeneratePortable))] [ExportContextMenuEntry(Header = nameof(Resources.GeneratePortable))]
[Shared] [Shared]
class GeneratePdbContextMenuEntry : IContextMenuEntry class GeneratePdbContextMenuEntry(LanguageService languageService) : IContextMenuEntry
{ {
public void Execute(TextViewContext context) public void Execute(TextViewContext context)
{ {
var assembly = (context.SelectedTreeNodes?.FirstOrDefault() as AssemblyTreeNode)?.LoadedAssembly; var assembly = (context.SelectedTreeNodes?.FirstOrDefault() as AssemblyTreeNode)?.LoadedAssembly;
if (assembly == null) if (assembly == null)
return; return;
GeneratePdbForAssembly(assembly); GeneratePdbForAssembly(assembly, languageService);
} }
public bool IsEnabled(TextViewContext context) => true; public bool IsEnabled(TextViewContext context) => true;
@ -60,7 +62,7 @@ namespace ICSharpCode.ILSpy
&& tn.LoadedAssembly.IsLoadedAsValidAssembly; && tn.LoadedAssembly.IsLoadedAsValidAssembly;
} }
internal static void GeneratePdbForAssembly(LoadedAssembly assembly) internal static void GeneratePdbForAssembly(LoadedAssembly assembly, LanguageService languageService)
{ {
var file = assembly.GetMetadataFileOrNull() as PEFile; var file = assembly.GetMetadataFileOrNull() as PEFile;
if (!PortablePdbWriter.HasCodeViewDebugDirectoryEntry(file)) if (!PortablePdbWriter.HasCodeViewDebugDirectoryEntry(file))
@ -75,7 +77,7 @@ namespace ICSharpCode.ILSpy
if (dlg.ShowDialog() != true) if (dlg.ShowDialog() != true)
return; return;
DockWorkspace dockWorkspace = DockWorkspace.Instance; DockWorkspace dockWorkspace = DockWorkspace.Instance;
DecompilationOptions options = LanguageService.Instance.CreateDecompilationOptions(dockWorkspace.ActiveTabPage); DecompilationOptions options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions();
string fileName = dlg.FileName; string fileName = dlg.FileName;
dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => { dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
AvalonEditTextOutput output = new AvalonEditTextOutput(); AvalonEditTextOutput output = new AvalonEditTextOutput();
@ -108,21 +110,21 @@ namespace ICSharpCode.ILSpy
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.GeneratePortable), MenuCategory = nameof(Resources.Save))] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.GeneratePortable), MenuCategory = nameof(Resources.Save))]
[Shared] [Shared]
class GeneratePdbMainMenuEntry : SimpleCommand class GeneratePdbMainMenuEntry(AssemblyTreeModel assemblyTreeModel, LanguageService languageService) : SimpleCommand
{ {
public override bool CanExecute(object parameter) public override bool CanExecute(object parameter)
{ {
return MainWindow.Instance.AssemblyTreeModel.SelectedNodes?.Count() == 1 return assemblyTreeModel.SelectedNodes?.Count() == 1
&& MainWindow.Instance.AssemblyTreeModel.SelectedNodes?.FirstOrDefault() is AssemblyTreeNode tn && assemblyTreeModel.SelectedNodes?.FirstOrDefault() is AssemblyTreeNode tn
&& !tn.LoadedAssembly.HasLoadError; && !tn.LoadedAssembly.HasLoadError;
} }
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
var assembly = (MainWindow.Instance.AssemblyTreeModel.SelectedNodes?.FirstOrDefault() as AssemblyTreeNode)?.LoadedAssembly; var assembly = (assemblyTreeModel.SelectedNodes?.FirstOrDefault() as AssemblyTreeNode)?.LoadedAssembly;
if (assembly == null) if (assembly == null)
return; return;
GeneratePdbContextMenuEntry.GeneratePdbForAssembly(assembly); GeneratePdbContextMenuEntry.GeneratePdbForAssembly(assembly, languageService);
} }
} }
} }

37
ILSpy/Commands/ILSpyCommands.cs

@ -1,37 +0,0 @@
// Copyright (c) 2018 Siegfried Pammer
//
// 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.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using ICSharpCode.ILSpy.Analyzers;
using ICSharpCode.ILSpy.Commands;
namespace ICSharpCode.ILSpy
{
static class ILSpyCommands
{
public static readonly AnalyzeCommand Analyze = new AnalyzeCommand();
public static readonly ManageAssemblyListsCommand ManageAssemblyListsCommand = new ManageAssemblyListsCommand();
public static readonly SetThemeCommand SetTheme = new SetThemeCommand();
}
}

6
ILSpy/Commands/ManageAssemblyListsCommand.cs

@ -25,12 +25,12 @@ namespace ICSharpCode.ILSpy
{ {
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.ManageAssembly_Lists), MenuIcon = "Images/AssemblyList", MenuCategory = nameof(Resources.Open), MenuOrder = 1.7)] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.ManageAssembly_Lists), MenuIcon = "Images/AssemblyList", MenuCategory = nameof(Resources.Open), MenuOrder = 1.7)]
[Shared] [Shared]
sealed class ManageAssemblyListsCommand : SimpleCommand sealed class ManageAssemblyListsCommand(SettingsService settingsService) : SimpleCommand
{ {
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
ManageAssemblyListsDialog dlg = new ManageAssemblyListsDialog(); ManageAssemblyListsDialog dlg = new ManageAssemblyListsDialog(settingsService);
dlg.Owner = MainWindow.Instance; dlg.Owner = App.Current.MainWindow;
dlg.ShowDialog(); dlg.ShowDialog();
} }
} }

2
ILSpy/Commands/OpenFromGacCommand.cs

@ -43,7 +43,7 @@ namespace ICSharpCode.ILSpy
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
OpenFromGacDialog dlg = new OpenFromGacDialog { OpenFromGacDialog dlg = new OpenFromGacDialog {
Owner = MainWindow.Instance Owner = App.Current.MainWindow
}; };
if (dlg.ShowDialog() == true) if (dlg.ShowDialog() == true)

7
ILSpy/Commands/Pdb2XmlCommand.cs

@ -26,6 +26,7 @@ using System.Threading.Tasks;
using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
@ -36,18 +37,18 @@ namespace ICSharpCode.ILSpy
{ {
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDumpPDBAsXML), MenuCategory = nameof(Resources.Open), MenuOrder = 2.6)] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDumpPDBAsXML), MenuCategory = nameof(Resources.Open), MenuOrder = 2.6)]
[Shared] [Shared]
sealed class Pdb2XmlCommand : SimpleCommand sealed class Pdb2XmlCommand(AssemblyTreeModel assemblyTreeModel) : SimpleCommand
{ {
public override bool CanExecute(object parameter) public override bool CanExecute(object parameter)
{ {
var selectedNodes = MainWindow.Instance.AssemblyTreeModel.SelectedNodes; var selectedNodes = assemblyTreeModel.SelectedNodes;
return selectedNodes?.Any() == true return selectedNodes?.Any() == true
&& selectedNodes.All(n => n is AssemblyTreeNode asm && !asm.LoadedAssembly.HasLoadError); && selectedNodes.All(n => n is AssemblyTreeNode asm && !asm.LoadedAssembly.HasLoadError);
} }
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
Execute(MainWindow.Instance.AssemblyTreeModel.SelectedNodes.OfType<AssemblyTreeNode>()); Execute(assemblyTreeModel.SelectedNodes.OfType<AssemblyTreeNode>());
} }
internal static void Execute(IEnumerable<AssemblyTreeNode> nodes) internal static void Execute(IEnumerable<AssemblyTreeNode> nodes)

11
ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs

@ -26,15 +26,8 @@ namespace ICSharpCode.ILSpy
{ {
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources._RemoveAssembliesWithLoadErrors), MenuCategory = nameof(Resources.Remove), MenuOrder = 2.6)] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources._RemoveAssembliesWithLoadErrors), MenuCategory = nameof(Resources.Remove), MenuOrder = 2.6)]
[Shared] [Shared]
class RemoveAssembliesWithLoadErrors : SimpleCommand class RemoveAssembliesWithLoadErrors(AssemblyTreeModel assemblyTreeModel) : SimpleCommand
{ {
private readonly AssemblyTreeModel assemblyTreeModel;
public RemoveAssembliesWithLoadErrors(AssemblyTreeModel assemblyTreeModel)
{
this.assemblyTreeModel = assemblyTreeModel;
}
public override bool CanExecute(object parameter) public override bool CanExecute(object parameter)
{ {
return assemblyTreeModel.AssemblyList.GetAssemblies().Any(l => l.HasLoadError); return assemblyTreeModel.AssemblyList.GetAssemblies().Any(l => l.HasLoadError);
@ -46,7 +39,7 @@ namespace ICSharpCode.ILSpy
{ {
if (!assembly.HasLoadError) if (!assembly.HasLoadError)
continue; continue;
var node = MainWindow.Instance.AssemblyTreeModel.FindAssemblyNode(assembly); var node = assemblyTreeModel.FindAssemblyNode(assembly);
if (node != null && node.CanDelete()) if (node != null && node.CanDelete())
node.Delete(); node.Delete();
} }

11
ILSpy/Commands/SaveCodeContextMenuEntry.cs

@ -35,11 +35,11 @@ namespace ICSharpCode.ILSpy.TextView
{ {
[ExportContextMenuEntry(Header = nameof(Resources._SaveCode), Category = nameof(Resources.Save), Icon = "Images/Save")] [ExportContextMenuEntry(Header = nameof(Resources._SaveCode), Category = nameof(Resources.Save), Icon = "Images/Save")]
[Shared] [Shared]
sealed class SaveCodeContextMenuEntry : IContextMenuEntry sealed class SaveCodeContextMenuEntry(LanguageService languageService) : IContextMenuEntry
{ {
public void Execute(TextViewContext context) public void Execute(TextViewContext context)
{ {
Execute(context.SelectedTreeNodes); Execute(context.SelectedTreeNodes, languageService);
} }
public bool IsEnabled(TextViewContext context) => true; public bool IsEnabled(TextViewContext context) => true;
@ -57,12 +57,11 @@ namespace ICSharpCode.ILSpy.TextView
|| (selectedNodes.Count > 1 && (selectedNodes.All(n => n is AssemblyTreeNode) || selectedNodes.All(n => n is IMemberTreeNode))); || (selectedNodes.Count > 1 && (selectedNodes.All(n => n is AssemblyTreeNode) || selectedNodes.All(n => n is IMemberTreeNode)));
} }
public static void Execute(IReadOnlyList<SharpTreeNode> selectedNodes) public static void Execute(IReadOnlyList<SharpTreeNode> selectedNodes, LanguageService languageService)
{ {
var settingsService = SettingsService.Instance;
var dockWorkspace = Docking.DockWorkspace.Instance; var dockWorkspace = Docking.DockWorkspace.Instance;
var currentLanguage = LanguageService.Instance.Language; var currentLanguage = languageService.Language;
var tabPage = dockWorkspace.ActiveTabPage; var tabPage = dockWorkspace.ActiveTabPage;
tabPage.ShowTextView(textView => { tabPage.ShowTextView(textView => {
if (selectedNodes.Count == 1 && selectedNodes[0] is ILSpyTreeNode singleSelection) if (selectedNodes.Count == 1 && selectedNodes[0] is ILSpyTreeNode singleSelection)
@ -88,7 +87,7 @@ namespace ICSharpCode.ILSpy.TextView
// Fallback: if nobody was able to handle the request, use default behavior. // Fallback: if nobody was able to handle the request, use default behavior.
// try to save all nodes to disk. // try to save all nodes to disk.
var options = LanguageService.Instance.CreateDecompilationOptions(dockWorkspace.ActiveTabPage); var options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions();
options.FullDecompilation = true; options.FullDecompilation = true;
textView.SaveToDisk(currentLanguage, selectedNodes.OfType<ILSpyTreeNode>(), options); textView.SaveToDisk(currentLanguage, selectedNodes.OfType<ILSpyTreeNode>(), options);
}); });

12
ILSpy/Commands/SaveCommand.cs

@ -28,16 +28,8 @@ namespace ICSharpCode.ILSpy
{ {
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources._SaveCode), MenuIcon = "Images/Save", MenuCategory = nameof(Resources.Save), MenuOrder = 0)] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources._SaveCode), MenuIcon = "Images/Save", MenuCategory = nameof(Resources.Save), MenuOrder = 0)]
[Shared] [Shared]
sealed class SaveCommand : CommandWrapper sealed class SaveCommand(AssemblyTreeModel assemblyTreeModel, LanguageService languageService) : CommandWrapper(ApplicationCommands.Save)
{ {
private AssemblyTreeModel assemblyTreeModel;
public SaveCommand(AssemblyTreeModel assemblyTreeModel)
: base(ApplicationCommands.Save)
{
this.assemblyTreeModel = assemblyTreeModel;
}
protected override void OnCanExecute(object sender, CanExecuteRoutedEventArgs e) protected override void OnCanExecute(object sender, CanExecuteRoutedEventArgs e)
{ {
e.Handled = true; e.Handled = true;
@ -46,7 +38,7 @@ namespace ICSharpCode.ILSpy
protected override void OnExecute(object sender, ExecutedRoutedEventArgs e) protected override void OnExecute(object sender, ExecutedRoutedEventArgs e)
{ {
SaveCodeContextMenuEntry.Execute(assemblyTreeModel.SelectedNodes.ToList()); SaveCodeContextMenuEntry.Execute(assemblyTreeModel.SelectedNodes.ToList(), languageService);
} }
} }
} }

9
ILSpy/Commands/SelectPdbContextMenuEntry.cs

@ -21,6 +21,7 @@ using System.IO;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler; using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
@ -29,7 +30,7 @@ namespace ICSharpCode.ILSpy
{ {
[ExportContextMenuEntry(Header = nameof(Resources.SelectPDB))] [ExportContextMenuEntry(Header = nameof(Resources.SelectPDB))]
[Shared] [Shared]
class SelectPdbContextMenuEntry : IContextMenuEntry class SelectPdbContextMenuEntry(AssemblyTreeModel assemblyTreeModel) : IContextMenuEntry
{ {
public async void Execute(TextViewContext context) public async void Execute(TextViewContext context)
{ {
@ -48,10 +49,10 @@ namespace ICSharpCode.ILSpy
await assembly.LoadDebugInfo(dlg.FileName); await assembly.LoadDebugInfo(dlg.FileName);
} }
var node = (AssemblyTreeNode)MainWindow.Instance.AssemblyTreeModel.FindNodeByPath(new[] { assembly.FileName }, true); var node = (AssemblyTreeNode)assemblyTreeModel.FindNodeByPath(new[] { assembly.FileName }, true);
node.UpdateToolTip(); node.UpdateToolTip();
MainWindow.Instance.AssemblyTreeModel.SelectNode(node); assemblyTreeModel.SelectNode(node);
MainWindow.Instance.AssemblyTreeModel.RefreshDecompiledView(); assemblyTreeModel.RefreshDecompiledView();
} }
public bool IsEnabled(TextViewContext context) => true; public bool IsEnabled(TextViewContext context) => true;

8
ILSpy/Commands/SetThemeCommand.cs

@ -1,13 +1,17 @@
 
using System.Composition;
namespace ICSharpCode.ILSpy.Commands namespace ICSharpCode.ILSpy.Commands
{ {
public class SetThemeCommand : SimpleCommand [Export]
[Shared]
public class SetThemeCommand(SettingsService settingsService) : SimpleCommand
{ {
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
if (parameter is string theme) if (parameter is string theme)
{ {
SettingsService.Instance.SessionSettings.Theme = theme; settingsService.SessionSettings.Theme = theme;
} }
} }
} }

9
ILSpy/Commands/SortAssemblyListCommand.cs

@ -20,6 +20,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Composition; using System.Composition;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpyX.TreeView; using ICSharpCode.ILSpyX.TreeView;
@ -29,22 +30,22 @@ namespace ICSharpCode.ILSpy
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._View), Header = nameof(Resources.SortAssembly_listName), MenuIcon = "Images/Sort", MenuCategory = nameof(Resources.View))] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._View), Header = nameof(Resources.SortAssembly_listName), MenuIcon = "Images/Sort", MenuCategory = nameof(Resources.View))]
[ExportToolbarCommand(ToolTip = nameof(Resources.SortAssemblyListName), ToolbarIcon = "Images/Sort", ToolbarCategory = nameof(Resources.View))] [ExportToolbarCommand(ToolTip = nameof(Resources.SortAssemblyListName), ToolbarIcon = "Images/Sort", ToolbarCategory = nameof(Resources.View))]
[Shared] [Shared]
sealed class SortAssemblyListCommand : SimpleCommand sealed class SortAssemblyListCommand(AssemblyTreeModel assemblyTreeModel) : SimpleCommand
{ {
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
MainWindow.Instance.AssemblyTreeModel.SortAssemblyList(); assemblyTreeModel.SortAssemblyList();
} }
} }
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._View), Header = nameof(Resources._CollapseTreeNodes), MenuIcon = "Images/CollapseAll", MenuCategory = nameof(Resources.View))] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._View), Header = nameof(Resources._CollapseTreeNodes), MenuIcon = "Images/CollapseAll", MenuCategory = nameof(Resources.View))]
[ExportToolbarCommand(ToolTip = nameof(Resources.CollapseTreeNodes), ToolbarIcon = "Images/CollapseAll", ToolbarCategory = nameof(Resources.View))] [ExportToolbarCommand(ToolTip = nameof(Resources.CollapseTreeNodes), ToolbarIcon = "Images/CollapseAll", ToolbarCategory = nameof(Resources.View))]
[Shared] [Shared]
sealed class CollapseAllCommand : SimpleCommand sealed class CollapseAllCommand(AssemblyTreeModel assemblyTreeModel) : SimpleCommand
{ {
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
MainWindow.Instance.AssemblyTreeModel.CollapseAll(); assemblyTreeModel.CollapseAll();
} }
} }

3
ILSpy/ContextMenuEntry.cs

@ -31,6 +31,7 @@ using ICSharpCode.ILSpyX.TreeView;
using TomsToolbox.Composition; using TomsToolbox.Composition;
using TomsToolbox.Essentials; using TomsToolbox.Essentials;
using TomsToolbox.Wpf.Composition;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
@ -222,7 +223,7 @@ namespace ICSharpCode.ILSpy
private ContextMenuProvider(Control control) private ContextMenuProvider(Control control)
{ {
entries = App.ExportProvider.GetExports<IContextMenuEntry, IContextMenuEntryMetadata>().ToArray(); entries = control.GetExportProvider().GetExports<IContextMenuEntry, IContextMenuEntryMetadata>().ToArray();
this.control = control; this.control = control;
} }

36
ILSpy/Docking/DockWorkspace.cs

@ -32,6 +32,7 @@ using AvalonDock.Layout.Serialization;
using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.ILSpy.Analyzers; using ICSharpCode.ILSpy.Analyzers;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Search; using ICSharpCode.ILSpy.Search;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpy.ViewModels;
@ -44,15 +45,21 @@ namespace ICSharpCode.ILSpy.Docking
{ {
public class DockWorkspace : ObservableObject, ILayoutUpdateStrategy public class DockWorkspace : ObservableObject, ILayoutUpdateStrategy
{ {
private static SessionSettings SessionSettings => SettingsService.Instance.SessionSettings; private static readonly IExportProvider exportProvider = App.ExportProvider;
private readonly IExportProvider exportProvider = App.ExportProvider; private static SettingsService SettingsService => exportProvider.GetExportedValue<SettingsService>();
private static LanguageService LanguageService => exportProvider.GetExportedValue<LanguageService>();
private static SessionSettings SessionSettings => SettingsService.SessionSettings;
public static readonly DockWorkspace Instance = new(); public static readonly DockWorkspace Instance = new();
private readonly ObservableCollection<TabPageModel> tabPages = []; private readonly ObservableCollection<TabPageModel> tabPages = [];
private DockingManager dockingManager; private DockingManager DockingManager => exportProvider.GetExportedValue<DockingManager>();
AssemblyTreeModel AssemblyTreeModel => exportProvider.GetExportedValue<AssemblyTreeModel>();
private DockWorkspace() private DockWorkspace()
{ {
@ -123,7 +130,7 @@ namespace ICSharpCode.ILSpy.Docking
public void AddTabPage(TabPageModel tabPage = null) public void AddTabPage(TabPageModel tabPage = null)
{ {
tabPages.Add(tabPage ?? new TabPageModel()); tabPages.Add(tabPage ?? new TabPageModel(AssemblyTreeModel, SettingsService, LanguageService));
} }
public ReadOnlyObservableCollection<TabPageModel> TabPages { get; } public ReadOnlyObservableCollection<TabPageModel> TabPages { get; }
@ -170,29 +177,28 @@ namespace ICSharpCode.ILSpy.Docking
{ {
if (state.DecompiledNodes != null) if (state.DecompiledNodes != null)
{ {
MainWindow.Instance.AssemblyTreeModel.SelectNodes(state.DecompiledNodes); AssemblyTreeModel.SelectNodes(state.DecompiledNodes);
} }
else else
{ {
MainWindow.Instance.AssemblyTreeModel.NavigateTo(new(state.ViewedUri, null)); AssemblyTreeModel.NavigateTo(new(state.ViewedUri, null));
} }
} }
} }
} }
public PaneModel ActivePane { public PaneModel ActivePane {
get => dockingManager?.ActiveContent as PaneModel; get => DockingManager?.ActiveContent as PaneModel;
set { set {
if (dockingManager is not null) if (DockingManager is not null)
dockingManager.ActiveContent = value; DockingManager.ActiveContent = value;
} }
} }
public void InitializeLayout(DockingManager manager) public void InitializeLayout()
{ {
this.dockingManager = manager; DockingManager.LayoutUpdateStrategy = this;
manager.LayoutUpdateStrategy = this; XmlLayoutSerializer serializer = new XmlLayoutSerializer(DockingManager);
XmlLayoutSerializer serializer = new XmlLayoutSerializer(manager);
serializer.LayoutSerializationCallback += LayoutSerializationCallback; serializer.LayoutSerializationCallback += LayoutSerializationCallback;
try try
{ {
@ -254,8 +260,8 @@ namespace ICSharpCode.ILSpy.Docking
} }
CloseAllTabs(); CloseAllTabs();
SessionSettings.DockLayout.Reset(); SessionSettings.DockLayout.Reset();
InitializeLayout(MainWindow.Instance.dockManager); InitializeLayout();
MainWindow.Instance.Dispatcher.BeginInvoke(DispatcherPriority.Background, (Action)MainWindow.Instance.AssemblyTreeModel.RefreshDecompiledView); App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, AssemblyTreeModel.RefreshDecompiledView);
} }
static readonly PropertyInfo previousContainerProperty = typeof(LayoutContent).GetProperty("PreviousContainer", BindingFlags.NonPublic | BindingFlags.Instance); static readonly PropertyInfo previousContainerProperty = typeof(LayoutContent).GetProperty("PreviousContainer", BindingFlags.NonPublic | BindingFlags.Instance);

7
ILSpy/ExtensionMethods.cs

@ -76,10 +76,11 @@ namespace ICSharpCode.ILSpy
return result; return result;
} }
public static ICompilation? GetTypeSystemWithCurrentOptionsOrNull(this MetadataFile file) public static ICompilation? GetTypeSystemWithCurrentOptionsOrNull(this MetadataFile file, SettingsService settingsService)
{ {
return LoadedAssemblyExtensions.GetLoadedAssembly(file) return file
.GetTypeSystemOrNull(DecompilerTypeSystem.GetOptions(SettingsService.Instance.DecompilerSettings)); .GetLoadedAssembly()
.GetTypeSystemOrNull(DecompilerTypeSystem.GetOptions(settingsService.DecompilerSettings));
} }
#region DPI independence #region DPI independence

4
ILSpy/Languages/CSharpILMixedLanguage.cs

@ -43,13 +43,13 @@ namespace ICSharpCode.ILSpy
[Export(typeof(Language))] [Export(typeof(Language))]
[Shared] [Shared]
class CSharpILMixedLanguage : ILLanguage class CSharpILMixedLanguage(SettingsService settingsService) : ILLanguage
{ {
public override string Name => "IL with C#"; public override string Name => "IL with C#";
protected override ReflectionDisassembler CreateDisassembler(ITextOutput output, DecompilationOptions options) protected override ReflectionDisassembler CreateDisassembler(ITextOutput output, DecompilationOptions options)
{ {
var displaySettings = SettingsService.Instance.DisplaySettings; var displaySettings = settingsService.DisplaySettings;
return new ReflectionDisassembler(output, return new ReflectionDisassembler(output,
new MixedMethodBodyDisassembler(output, options) { new MixedMethodBodyDisassembler(output, options) {
DetectControlStructure = detectControlStructure, DetectControlStructure = detectControlStructure,

38
ILSpy/Languages/CSharpLanguage.cs

@ -38,6 +38,7 @@ using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Output; using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.Solution; using ICSharpCode.Decompiler.Solution;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
@ -55,25 +56,18 @@ namespace ICSharpCode.ILSpy
[Shared] [Shared]
public class CSharpLanguage : Language public class CSharpLanguage : Language
{ {
readonly IReadOnlyCollection<IResourceFileHandler> resourceFileHandlers;
string name = "C#"; string name = "C#";
bool showAllMembers = false; bool showAllMembers = false;
int transformCount = int.MaxValue; int transformCount = int.MaxValue;
public CSharpLanguage(IEnumerable<IResourceFileHandler> resourceFileHandlers)
{
this.resourceFileHandlers = resourceFileHandlers.ToArray();
}
#if DEBUG #if DEBUG
internal static IEnumerable<CSharpLanguage> GetDebugLanguages(IReadOnlyCollection<IResourceFileHandler> resourceFileHandlers) internal static IEnumerable<CSharpLanguage> GetDebugLanguages()
{ {
string lastTransformName = "no transforms"; string lastTransformName = "no transforms";
int transformCount = 0; int transformCount = 0;
foreach (var transform in CSharpDecompiler.GetAstTransforms()) foreach (var transform in CSharpDecompiler.GetAstTransforms())
{ {
yield return new CSharpLanguage(resourceFileHandlers) { yield return new() {
transformCount = transformCount, transformCount = transformCount,
name = "C# - " + lastTransformName, name = "C# - " + lastTransformName,
showAllMembers = true showAllMembers = true
@ -81,7 +75,7 @@ namespace ICSharpCode.ILSpy
lastTransformName = "after " + transform.GetType().Name; lastTransformName = "after " + transform.GetType().Name;
transformCount++; transformCount++;
} }
yield return new CSharpLanguage(resourceFileHandlers) { yield return new() {
name = "C# - " + lastTransformName, name = "C# - " + lastTransformName,
showAllMembers = true showAllMembers = true
}; };
@ -364,15 +358,15 @@ namespace ICSharpCode.ILSpy
void AddReferenceWarningMessage(MetadataFile module, ITextOutput output) void AddReferenceWarningMessage(MetadataFile module, ITextOutput output)
{ {
var loadedAssembly = MainWindow.Instance.AssemblyTreeModel.AssemblyList.GetAssemblies().FirstOrDefault(la => la.GetMetadataFileOrNull() == module); var loadedAssembly = AssemblyTreeModel.AssemblyList.GetAssemblies().FirstOrDefault(la => la.GetMetadataFileOrNull() == module);
if (loadedAssembly == null || !loadedAssembly.LoadedAssemblyReferencesInfo.HasErrors) if (loadedAssembly == null || !loadedAssembly.LoadedAssemblyReferencesInfo.HasErrors)
return; return;
string line1 = Properties.Resources.WarningSomeAssemblyReference; string line1 = Properties.Resources.WarningSomeAssemblyReference;
string line2 = Properties.Resources.PropertyManuallyMissingReferencesListLoadedAssemblies; string line2 = Properties.Resources.PropertyManuallyMissingReferencesListLoadedAssemblies;
AddWarningMessage(module, output, line1, line2, Properties.Resources.ShowAssemblyLoad, Images.ViewCode, delegate { AddWarningMessage(module, output, line1, line2, Properties.Resources.ShowAssemblyLoad, Images.ViewCode, delegate {
ILSpyTreeNode assemblyNode = MainWindow.Instance.AssemblyTreeModel.FindTreeNode(module); ILSpyTreeNode assemblyNode = AssemblyTreeModel.FindTreeNode(module);
assemblyNode.EnsureLazyChildren(); assemblyNode.EnsureLazyChildren();
MainWindow.Instance.AssemblyTreeModel.SelectNode(assemblyNode.Children.OfType<ReferenceFolderTreeNode>().Single()); AssemblyTreeModel.SelectNode(assemblyNode.Children.OfType<ReferenceFolderTreeNode>().Single());
}); });
} }
@ -436,7 +430,7 @@ namespace ICSharpCode.ILSpy
{ {
options.DecompilerSettings.UseSdkStyleProjectFormat = false; options.DecompilerSettings.UseSdkStyleProjectFormat = false;
} }
var decompiler = new ILSpyWholeProjectDecompiler(assembly, options, resourceFileHandlers) { var decompiler = new ILSpyWholeProjectDecompiler(assembly, options) {
ProgressIndicator = options.Progress ProgressIndicator = options.Progress
}; };
return decompiler.DecompileProject(module, options.SaveAsProjectDirectory, new TextOutputWriter(output), options.CancellationToken); return decompiler.DecompileProject(module, options.SaveAsProjectDirectory, new TextOutputWriter(output), options.CancellationToken);
@ -549,20 +543,18 @@ namespace ICSharpCode.ILSpy
{ {
readonly LoadedAssembly assembly; readonly LoadedAssembly assembly;
readonly DecompilationOptions options; readonly DecompilationOptions options;
private readonly IReadOnlyCollection<IResourceFileHandler> resourceFileHandlers;
public ILSpyWholeProjectDecompiler(LoadedAssembly assembly, DecompilationOptions options, IReadOnlyCollection<IResourceFileHandler> resourceFileHandlers) public ILSpyWholeProjectDecompiler(LoadedAssembly assembly, DecompilationOptions options)
: base(options.DecompilerSettings, assembly.GetAssemblyResolver(options.DecompilerSettings.AutoLoadAssemblyReferences, options.DecompilerSettings.ApplyWindowsRuntimeProjections), null, assembly.GetAssemblyReferenceClassifier(options.DecompilerSettings.ApplyWindowsRuntimeProjections), assembly.GetDebugInfoOrNull()) : base(options.DecompilerSettings, assembly.GetAssemblyResolver(options.DecompilerSettings.AutoLoadAssemblyReferences, options.DecompilerSettings.ApplyWindowsRuntimeProjections), null, assembly.GetAssemblyReferenceClassifier(options.DecompilerSettings.ApplyWindowsRuntimeProjections), assembly.GetDebugInfoOrNull())
{ {
this.assembly = assembly; this.assembly = assembly;
this.options = options; this.options = options;
this.resourceFileHandlers = resourceFileHandlers;
} }
protected override IEnumerable<ProjectItemInfo> WriteResourceToFile(string fileName, string resourceName, Stream entryStream) protected override IEnumerable<ProjectItemInfo> WriteResourceToFile(string fileName, string resourceName, Stream entryStream)
{ {
var context = new ResourceFileHandlerContext(options); var context = new ResourceFileHandlerContext(options);
foreach (var handler in resourceFileHandlers) foreach (var handler in ResourceFileHandlers)
{ {
if (handler.CanHandle(fileName, context)) if (handler.CanHandle(fileName, context))
{ {
@ -576,19 +568,19 @@ namespace ICSharpCode.ILSpy
} }
} }
static CSharpAmbience CreateAmbience() CSharpAmbience CreateAmbience()
{ {
CSharpAmbience ambience = new CSharpAmbience(); CSharpAmbience ambience = new CSharpAmbience();
// Do not forget to update CSharpAmbienceTests.ILSpyMainTreeViewTypeFlags, if this ever changes. // Do not forget to update CSharpAmbienceTests.ILSpyMainTreeViewTypeFlags, if this ever changes.
ambience.ConversionFlags = ConversionFlags.ShowTypeParameterList | ConversionFlags.PlaceReturnTypeAfterParameterList; ambience.ConversionFlags = ConversionFlags.ShowTypeParameterList | ConversionFlags.PlaceReturnTypeAfterParameterList;
if (SettingsService.Instance.DecompilerSettings.LiftNullables) if (SettingsService.DecompilerSettings.LiftNullables)
{ {
ambience.ConversionFlags |= ConversionFlags.UseNullableSpecifierForValueTypes; ambience.ConversionFlags |= ConversionFlags.UseNullableSpecifierForValueTypes;
} }
return ambience; return ambience;
} }
static string EntityToString(IEntity entity, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName) string EntityToString(IEntity entity, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName)
{ {
// Do not forget to update CSharpAmbienceTests, if this ever changes. // Do not forget to update CSharpAmbienceTests, if this ever changes.
var ambience = CreateAmbience(); var ambience = CreateAmbience();
@ -784,7 +776,7 @@ namespace ICSharpCode.ILSpy
public override bool ShowMember(IEntity member) public override bool ShowMember(IEntity member)
{ {
MetadataFile assembly = member.ParentModule.MetadataFile; MetadataFile assembly = member.ParentModule.MetadataFile;
return showAllMembers || !CSharpDecompiler.MemberIsHidden(assembly, member.MetadataToken, SettingsService.Instance.DecompilerSettings); return showAllMembers || !CSharpDecompiler.MemberIsHidden(assembly, member.MetadataToken, SettingsService.DecompilerSettings);
} }
public override RichText GetRichTextTooltip(IEntity entity) public override RichText GetRichTextTooltip(IEntity entity)
@ -793,7 +785,7 @@ namespace ICSharpCode.ILSpy
var output = new StringWriter(); var output = new StringWriter();
var decoratedWriter = new TextWriterTokenWriter(output); var decoratedWriter = new TextWriterTokenWriter(output);
var writer = new CSharpHighlightingTokenWriter(TokenWriter.InsertRequiredSpaces(decoratedWriter), locatable: decoratedWriter); var writer = new CSharpHighlightingTokenWriter(TokenWriter.InsertRequiredSpaces(decoratedWriter), locatable: decoratedWriter);
var settings = SettingsService.Instance.DecompilerSettings; var settings = SettingsService.DecompilerSettings;
if (!settings.LiftNullables) if (!settings.LiftNullables)
{ {
flags &= ~ConversionFlags.UseNullableSpecifierForValueTypes; flags &= ~ConversionFlags.UseNullableSpecifierForValueTypes;

6
ILSpy/Languages/ILLanguage.cs

@ -31,6 +31,7 @@ using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
@ -58,7 +59,7 @@ namespace ICSharpCode.ILSpy
protected virtual ReflectionDisassembler CreateDisassembler(ITextOutput output, DecompilationOptions options) protected virtual ReflectionDisassembler CreateDisassembler(ITextOutput output, DecompilationOptions options)
{ {
var displaySettings = SettingsService.Instance.DisplaySettings; var displaySettings = SettingsService.DisplaySettings;
output.IndentationString = options.DecompilerSettings.CSharpFormattingOptions.IndentationString; output.IndentationString = options.DecompilerSettings.CSharpFormattingOptions.IndentationString;
return new ReflectionDisassembler(output, options.CancellationToken) { return new ReflectionDisassembler(output, options.CancellationToken) {
DetectControlStructure = detectControlStructure, DetectControlStructure = detectControlStructure,
@ -198,10 +199,9 @@ namespace ICSharpCode.ILSpy
public override RichText GetRichTextTooltip(IEntity entity) public override RichText GetRichTextTooltip(IEntity entity)
{ {
var output = new AvalonEditTextOutput() { IgnoreNewLineAndIndent = true }; var output = new AvalonEditTextOutput() { IgnoreNewLineAndIndent = true };
var settingsService = SettingsService.Instance;
var dockWorkspace = DockWorkspace.Instance; var dockWorkspace = DockWorkspace.Instance;
var disasm = CreateDisassembler(output, LanguageService.Instance.CreateDecompilationOptions(dockWorkspace.ActiveTabPage)); var disasm = CreateDisassembler(output, dockWorkspace.ActiveTabPage.CreateDecompilationOptions());
MetadataFile module = entity.ParentModule?.MetadataFile; MetadataFile module = entity.ParentModule?.MetadataFile;
if (module == null) if (module == null)
{ {

8
ILSpy/Languages/Language.cs

@ -18,6 +18,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata; using System.Reflection.Metadata;
using System.Reflection.PortableExecutable; using System.Reflection.PortableExecutable;
using System.Text; using System.Text;
@ -29,6 +30,7 @@ using ICSharpCode.Decompiler.Solution;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpyX.Abstractions; using ICSharpCode.ILSpyX.Abstractions;
@ -42,6 +44,12 @@ namespace ICSharpCode.ILSpy
/// </remarks> /// </remarks>
public abstract class Language : ILanguage public abstract class Language : ILanguage
{ {
public static SettingsService SettingsService { get; } = App.ExportProvider.GetExportedValue<SettingsService>();
public static AssemblyTreeModel AssemblyTreeModel { get; } = App.ExportProvider.GetExportedValue<AssemblyTreeModel>();
public static ICollection<IResourceFileHandler> ResourceFileHandlers { get; } = App.ExportProvider.GetExportedValues<IResourceFileHandler>().ToArray();
/// <summary> /// <summary>
/// Gets the name of the language (as shown in the UI) /// Gets the name of the language (as shown in the UI)
/// </summary> /// </summary>

18
ILSpy/Languages/LanguageService.cs

@ -21,26 +21,23 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Composition;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
using TomsToolbox.Wpf; using TomsToolbox.Wpf;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
[Export]
[Shared]
public class LanguageService : ObservableObjectBase public class LanguageService : ObservableObjectBase
{ {
public static readonly LanguageService Instance = new(App.ExportProvider.GetExportedValues<Language>(), App.ExportProvider.GetExportedValues<IResourceFileHandler>(), SettingsService.Instance);
private readonly LanguageSettings languageSettings; private readonly LanguageSettings languageSettings;
private readonly SettingsService settingsService;
public LanguageService(IEnumerable<Language> languages, IEnumerable<IResourceFileHandler> resourceFileHandlers, SettingsService settingsService) public LanguageService(IEnumerable<Language> languages, SettingsService settingsService)
{ {
this.settingsService = settingsService;
languageSettings = settingsService.SessionSettings.LanguageSettings; languageSettings = settingsService.SessionSettings.LanguageSettings;
var sortedLanguages = languages.ToList(); var sortedLanguages = languages.ToList();
@ -48,7 +45,7 @@ namespace ICSharpCode.ILSpy
sortedLanguages.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.Ordinal)); sortedLanguages.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.Ordinal));
#if DEBUG #if DEBUG
sortedLanguages.AddRange(ILAstLanguage.GetDebugLanguages()); sortedLanguages.AddRange(ILAstLanguage.GetDebugLanguages());
sortedLanguages.AddRange(CSharpLanguage.GetDebugLanguages(resourceFileHandlers.ToArray())); sortedLanguages.AddRange(CSharpLanguage.GetDebugLanguages());
#endif #endif
AllLanguages = sortedLanguages.AsReadOnly(); AllLanguages = sortedLanguages.AsReadOnly();
@ -143,10 +140,5 @@ namespace ICSharpCode.ILSpy
languageSettings.LanguageVersionId = languageVersion?.Version; languageSettings.LanguageVersionId = languageVersion?.Version;
} }
} }
public DecompilationOptions CreateDecompilationOptions(TabPageModel tabPage)
{
return new(LanguageVersion, settingsService.DecompilerSettings, settingsService.DisplaySettings) { Progress = tabPage.Content as IProgress<DecompilationProgress> };
}
} }
} }

10
ILSpy/MainWindow.xaml

@ -18,6 +18,8 @@
xmlns:themes="clr-namespace:ICSharpCode.ILSpy.Themes" xmlns:themes="clr-namespace:ICSharpCode.ILSpy.Themes"
xmlns:toms="urn:TomsToolbox" xmlns:toms="urn:TomsToolbox"
xmlns:viewModels="clr-namespace:ICSharpCode.ILSpy.ViewModels" xmlns:viewModels="clr-namespace:ICSharpCode.ILSpy.ViewModels"
xmlns:composition="urn:TomsToolbox.Composition"
xmlns:commands="clr-namespace:ICSharpCode.ILSpy.Commands"
d:DataContext="{d:DesignInstance local:MainWindowViewModel}"> d:DataContext="{d:DesignInstance local:MainWindowViewModel}">
<Window.Resources> <Window.Resources>
@ -36,7 +38,7 @@
</b:Interaction.Behaviors> </b:Interaction.Behaviors>
<Window.InputBindings> <Window.InputBindings>
<KeyBinding Key="R" Modifiers="Control" Command="{x:Static local:ILSpyCommands.Analyze}" /> <KeyBinding Key="R" Modifiers="Control" Command="{Binding AnalyzeCommand}" />
<KeyBinding Key="Z" Modifiers="Control" Command="{x:Static NavigationCommands.BrowseBack}" /> <KeyBinding Key="Z" Modifiers="Control" Command="{x:Static NavigationCommands.BrowseBack}" />
</Window.InputBindings> </Window.InputBindings>
@ -60,7 +62,7 @@
<MenuItem Header="{x:Static properties:Resources.Theme}" ItemsSource="{x:Static themes:ThemeManager.AllThemes}"> <MenuItem Header="{x:Static properties:Resources.Theme}" ItemsSource="{x:Static themes:ThemeManager.AllThemes}">
<MenuItem.ItemContainerStyle> <MenuItem.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource {x:Type MenuItem}}"> <Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource {x:Type MenuItem}}">
<Setter Property="Command" Value="{x:Static local:ILSpyCommands.SetTheme}" /> <Setter Property="Command" Value="{composition:Import {x:Type commands:SetThemeCommand}}" />
<Setter Property="CommandParameter" Value="{Binding}" /> <Setter Property="CommandParameter" Value="{Binding}" />
<Setter Property="IsCheckable" Value="True" /> <Setter Property="IsCheckable" Value="True" />
<!-- Required by AvalonDock's MenuItem style to show the checkmark --> <!-- Required by AvalonDock's MenuItem style to show the checkmark -->
@ -123,7 +125,7 @@
ToolTip="{x:Static properties:Resources.SelectAssemblyListDropdownTooltip}" ToolTip="{x:Static properties:Resources.SelectAssemblyListDropdownTooltip}"
SelectedItem="{Binding SessionSettings.ActiveAssemblyList}" /> SelectedItem="{Binding SessionSettings.ActiveAssemblyList}" />
</Grid> </Grid>
<Button Command="{x:Static local:ILSpyCommands.ManageAssemblyListsCommand}" <Button Command="{composition:Import {x:Type local:ManageAssemblyListsCommand}}"
ToolTip="{x:Static properties:Resources.ManageAssemblyLists}"> ToolTip="{x:Static properties:Resources.ManageAssemblyLists}">
<Image Width="16" Height="16" Source="{controls:XamlResource Images/AssemblyList}" <Image Width="16" Height="16" Source="{controls:XamlResource Images/AssemblyList}"
Style="{StaticResource DarkModeAwareImageStyle}" /> Style="{StaticResource DarkModeAwareImageStyle}" />
@ -186,7 +188,7 @@
</StatusBarItem> </StatusBarItem>
</StatusBar> </StatusBar>
<avalondock:DockingManager x:Name="dockManager" <avalondock:DockingManager x:Name="DockManager"
DataContext="{Binding Workspace}" DataContext="{Binding Workspace}"
AnchorablesSource="{Binding ToolPanes}" AnchorablesSource="{Binding ToolPanes}"
DocumentsSource="{Binding TabPages}" DocumentsSource="{Binding TabPages}"

59
ILSpy/MainWindow.xaml.cs

@ -17,7 +17,9 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Composition;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
@ -30,7 +32,6 @@ using System.Windows.Threading;
using AvalonDock.Layout.Serialization; using AvalonDock.Layout.Serialization;
using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.Updates; using ICSharpCode.ILSpy.Updates;
using ICSharpCode.ILSpyX.FileLoaders; using ICSharpCode.ILSpyX.FileLoaders;
@ -44,25 +45,22 @@ namespace ICSharpCode.ILSpy
/// <summary> /// <summary>
/// The main window of the application. /// The main window of the application.
/// </summary> /// </summary>
partial class MainWindow : Window [Export]
[Shared]
#pragma warning disable MEF003 // Main window is a singleton
partial class MainWindow
{ {
static MainWindow instance; private readonly AssemblyTreeModel assemblyTreeModel;
private readonly IEnumerable<IFileLoader> fileLoaders;
private readonly MenuService menuService;
private readonly SettingsService settingsService;
private readonly MainWindowViewModel mainWindowViewModel = new(); public MainWindow(MainWindowViewModel mainWindowViewModel, AssemblyTreeModel assemblyTreeModel, IEnumerable<IFileLoader> fileLoaders, MenuService menuService, SettingsService settingsService)
public static MainWindow Instance {
get { return instance; }
}
public AssemblyTreeModel AssemblyTreeModel {
get {
return App.ExportProvider.GetExportedValue<AssemblyTreeModel>();
}
}
public MainWindow()
{ {
instance = this; this.assemblyTreeModel = assemblyTreeModel;
this.fileLoaders = fileLoaders;
this.menuService = menuService;
this.settingsService = settingsService;
// Make sure Images are initialized on the UI thread. // Make sure Images are initialized on the UI thread.
this.Icon = Images.ILSpyIcon; this.Icon = Images.ILSpyIcon;
@ -74,12 +72,12 @@ namespace ICSharpCode.ILSpy
InitFileLoaders(); InitFileLoaders();
Dispatcher.BeginInvoke(DispatcherPriority.Background, () => { Dispatcher.BeginInvoke(DispatcherPriority.Background, () => {
mainWindowViewModel.Workspace.InitializeLayout(dockManager); mainWindowViewModel.Workspace.InitializeLayout();
MenuService.Instance.Init(mainMenu, toolBar, InputBindings); menuService.Init(mainMenu, toolBar, InputBindings);
Dispatcher.BeginInvoke(DispatcherPriority.Background, () => { Dispatcher.BeginInvoke(DispatcherPriority.Background, () => {
AssemblyTreeModel.Initialize(); assemblyTreeModel.Initialize();
AssemblyTreeModel.Show(); assemblyTreeModel.Show();
}); });
}); });
} }
@ -97,9 +95,8 @@ namespace ICSharpCode.ILSpy
void InitFileLoaders() void InitFileLoaders()
{ {
// TODO // TODO
foreach (var loader in App.ExportProvider.GetExportedValues<IFileLoader>()) foreach (var loader in fileLoaders)
{ {
} }
} }
@ -113,7 +110,7 @@ namespace ICSharpCode.ILSpy
var source = PresentationSource.FromVisual(this); var source = PresentationSource.FromVisual(this);
var sessionSettings = SettingsService.Instance.SessionSettings; var sessionSettings = settingsService.SessionSettings;
// Validate and Set Window Bounds // Validate and Set Window Bounds
var windowBounds = Rect.Transform(sessionSettings.WindowBounds, source?.CompositionTarget?.TransformToDevice ?? Matrix.Identity); var windowBounds = Rect.Transform(sessionSettings.WindowBounds, source?.CompositionTarget?.TransformToDevice ?? Matrix.Identity);
@ -185,7 +182,7 @@ namespace ICSharpCode.ILSpy
else else
{ {
updatePanel.Visibility = Visibility.Collapsed; updatePanel.Visibility = Visibility.Collapsed;
string downloadUrl = await NotifyOfUpdatesStrategy.CheckForUpdatesAsync(SettingsService.Instance.SpySettings); string downloadUrl = await NotifyOfUpdatesStrategy.CheckForUpdatesAsync(settingsService.SpySettings);
AdjustUpdateUIAfterCheck(downloadUrl, true); AdjustUpdateUIAfterCheck(downloadUrl, true);
} }
} }
@ -243,22 +240,22 @@ namespace ICSharpCode.ILSpy
base.OnStateChanged(e); base.OnStateChanged(e);
// store window state in settings only if it's not minimized // store window state in settings only if it's not minimized
if (this.WindowState != WindowState.Minimized) if (this.WindowState != WindowState.Minimized)
SettingsService.Instance.SessionSettings.WindowState = this.WindowState; settingsService.SessionSettings.WindowState = this.WindowState;
} }
protected override void OnClosing(CancelEventArgs e) protected override void OnClosing(CancelEventArgs e)
{ {
base.OnClosing(e); base.OnClosing(e);
var snapshot = SettingsService.Instance.CreateSnapshot(); var snapshot = settingsService.CreateSnapshot();
var sessionSettings = snapshot.GetSettings<SessionSettings>(); var sessionSettings = snapshot.GetSettings<SessionSettings>();
sessionSettings.ActiveAssemblyList = AssemblyTreeModel.AssemblyList.ListName; sessionSettings.ActiveAssemblyList = assemblyTreeModel.AssemblyList.ListName;
sessionSettings.ActiveTreeViewPath = AssemblyTreeModel.SelectedPath; sessionSettings.ActiveTreeViewPath = assemblyTreeModel.SelectedPath;
sessionSettings.ActiveAutoLoadedAssembly = GetAutoLoadedAssemblyNode(AssemblyTreeModel.SelectedItem); sessionSettings.ActiveAutoLoadedAssembly = GetAutoLoadedAssemblyNode(assemblyTreeModel.SelectedItem);
sessionSettings.WindowBounds = this.RestoreBounds; sessionSettings.WindowBounds = this.RestoreBounds;
sessionSettings.DockLayout.Serialize(new XmlLayoutSerializer(dockManager)); sessionSettings.DockLayout.Serialize(new XmlLayoutSerializer(DockManager));
snapshot.Save(); snapshot.Save();
} }

16
ILSpy/MainWindowViewModel.cs

@ -16,6 +16,10 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System.Composition;
using ICSharpCode.ILSpy.Analyzers;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
@ -23,11 +27,15 @@ using TomsToolbox.Wpf;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
class MainWindowViewModel : ObservableObject [Export]
[Shared]
public class MainWindowViewModel(AssemblyTreeModel assemblyTreeModel, AnalyzerTreeViewModel analyzerTreeViewModel, SettingsService settingsService, LanguageService languageService) : ObservableObject
{ {
public DockWorkspace Workspace => DockWorkspace.Instance; public DockWorkspace Workspace => DockWorkspace.Instance;
public SessionSettings SessionSettings => SettingsService.Instance.SessionSettings; public SessionSettings SessionSettings => settingsService.SessionSettings;
public LanguageService LanguageService => LanguageService.Instance; public LanguageService LanguageService => languageService;
public AssemblyListManager AssemblyListManager => SettingsService.Instance.AssemblyListManager; public AssemblyListManager AssemblyListManager => settingsService.AssemblyListManager;
public AnalyzeCommand AnalyzeCommand { get; } = new(assemblyTreeModel, analyzerTreeViewModel);
} }
} }

2
ILSpy/Metadata/CorTables/EventTableTreeNode.cs

@ -94,7 +94,7 @@ namespace ICSharpCode.ILSpy.Metadata
IEntity IMemberTreeNode.Member { IEntity IMemberTreeNode.Member {
get { get {
return ((MetadataModule)metadataFile.GetTypeSystemWithCurrentOptionsOrNull()?.MainModule)?.GetDefinition(handle); return ((MetadataModule)metadataFile.GetTypeSystemWithCurrentOptionsOrNull(SettingsService)?.MainModule)?.GetDefinition(handle);
} }
} }

2
ILSpy/Metadata/CorTables/FieldTableTreeNode.cs

@ -95,7 +95,7 @@ namespace ICSharpCode.ILSpy.Metadata
public string NameTooltip => $"{MetadataTokens.GetHeapOffset(fieldDef.Name):X} \"{Name}\""; public string NameTooltip => $"{MetadataTokens.GetHeapOffset(fieldDef.Name):X} \"{Name}\"";
IEntity IMemberTreeNode.Member => ((MetadataModule)metadataFile.GetTypeSystemWithCurrentOptionsOrNull()?.MainModule)?.GetDefinition(handle); IEntity IMemberTreeNode.Member => ((MetadataModule)metadataFile.GetTypeSystemWithCurrentOptionsOrNull(SettingsService)?.MainModule)?.GetDefinition(handle);
[ColumnInfo("X8", Kind = ColumnKind.HeapOffset)] [ColumnInfo("X8", Kind = ColumnKind.HeapOffset)]
public int Signature => MetadataTokens.GetHeapOffset(fieldDef.Signature); public int Signature => MetadataTokens.GetHeapOffset(fieldDef.Signature);

2
ILSpy/Metadata/CorTables/MethodTableTreeNode.cs

@ -131,7 +131,7 @@ namespace ICSharpCode.ILSpy.Metadata
} }
} }
IEntity IMemberTreeNode.Member => ((MetadataModule)metadataFile.GetTypeSystemWithCurrentOptionsOrNull()?.MainModule)?.GetDefinition(handle); IEntity IMemberTreeNode.Member => ((MetadataModule)metadataFile.GetTypeSystemWithCurrentOptionsOrNull(SettingsService)?.MainModule)?.GetDefinition(handle);
public MethodDefEntry(MetadataFile metadataFile, MethodDefinitionHandle handle) public MethodDefEntry(MetadataFile metadataFile, MethodDefinitionHandle handle)
{ {

2
ILSpy/Metadata/CorTables/PropertyTableTreeNode.cs

@ -92,7 +92,7 @@ namespace ICSharpCode.ILSpy.Metadata
public string NameTooltip => $"{MetadataTokens.GetHeapOffset(propertyDef.Name):X} \"{Name}\""; public string NameTooltip => $"{MetadataTokens.GetHeapOffset(propertyDef.Name):X} \"{Name}\"";
IEntity IMemberTreeNode.Member => ((MetadataModule)metadataFile.GetTypeSystemWithCurrentOptionsOrNull()?.MainModule).GetDefinition(handle); IEntity IMemberTreeNode.Member => ((MetadataModule)metadataFile.GetTypeSystemWithCurrentOptionsOrNull(SettingsService)?.MainModule)?.GetDefinition(handle);
[ColumnInfo("X8", Kind = ColumnKind.HeapOffset)] [ColumnInfo("X8", Kind = ColumnKind.HeapOffset)]
public int Signature => MetadataTokens.GetHeapOffset(propertyDef.Signature); public int Signature => MetadataTokens.GetHeapOffset(propertyDef.Signature);

2
ILSpy/Metadata/CorTables/TypeDefTableTreeNode.cs

@ -173,7 +173,7 @@ namespace ICSharpCode.ILSpy.Metadata
} }
} }
IEntity IMemberTreeNode.Member => ((MetadataModule)metadataFile.GetTypeSystemWithCurrentOptionsOrNull()?.MainModule).GetDefinition(handle); IEntity IMemberTreeNode.Member => ((MetadataModule)metadataFile.GetTypeSystemWithCurrentOptionsOrNull(SettingsService)?.MainModule)?.GetDefinition(handle);
public TypeDefEntry(MetadataFile metadataFile, TypeDefinitionHandle handle) public TypeDefEntry(MetadataFile metadataFile, TypeDefinitionHandle handle)
{ {

2
ILSpy/Metadata/DebugMetadataTablesTreeNode.cs

@ -58,7 +58,7 @@ namespace ICSharpCode.ILSpy.Metadata
if (ShowTable(TableIndex.CustomDebugInformation)) if (ShowTable(TableIndex.CustomDebugInformation))
this.Children.Add(new CustomDebugInformationTableTreeNode(metadataFile)); this.Children.Add(new CustomDebugInformationTableTreeNode(metadataFile));
bool ShowTable(TableIndex table) => !SettingsService.Instance.DisplaySettings.HideEmptyMetadataTables || metadataFile.Metadata.GetTableRowCount(table) > 0; bool ShowTable(TableIndex table) => !SettingsService.DisplaySettings.HideEmptyMetadataTables || metadataFile.Metadata.GetTableRowCount(table) > 0;
} }
public override bool View(TabPageModel tabPage) public override bool View(TabPageModel tabPage)

5
ILSpy/Metadata/MetadataProtocolHandler.cs

@ -21,20 +21,21 @@ using System.Linq;
using System.Reflection.Metadata; using System.Reflection.Metadata;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
namespace ICSharpCode.ILSpy.Metadata namespace ICSharpCode.ILSpy.Metadata
{ {
[Export(typeof(IProtocolHandler))] [Export(typeof(IProtocolHandler))]
[Shared] [Shared]
class MetadataProtocolHandler : IProtocolHandler class MetadataProtocolHandler(AssemblyTreeModel assemblyTreeModel) : IProtocolHandler
{ {
public ILSpyTreeNode Resolve(string protocol, MetadataFile module, Handle handle, out bool newTabPage) public ILSpyTreeNode Resolve(string protocol, MetadataFile module, Handle handle, out bool newTabPage)
{ {
newTabPage = true; newTabPage = true;
if (protocol != "metadata") if (protocol != "metadata")
return null; return null;
var assemblyTreeNode = MainWindow.Instance.AssemblyTreeModel.FindTreeNode(module) as AssemblyTreeNode; var assemblyTreeNode = assemblyTreeModel.FindTreeNode(module) as AssemblyTreeNode;
if (assemblyTreeNode == null) if (assemblyTreeNode == null)
return null; return null;
var mxNode = assemblyTreeNode.Children.OfType<MetadataTreeNode>().FirstOrDefault(); var mxNode = assemblyTreeNode.Children.OfType<MetadataTreeNode>().FirstOrDefault();

2
ILSpy/Metadata/MetadataTablesTreeNode.cs

@ -50,7 +50,7 @@ namespace ICSharpCode.ILSpy.Metadata
} }
} }
internal static bool ShowTable(TableIndex table, MetadataReader metadata) => !SettingsService.Instance.DisplaySettings.HideEmptyMetadataTables || metadata.GetTableRowCount(table) > 0; internal static bool ShowTable(TableIndex table, MetadataReader metadata) => !SettingsService.DisplaySettings.HideEmptyMetadataTables || metadata.GetTableRowCount(table) > 0;
internal static MetadataTableTreeNode CreateTableTreeNode(TableIndex table, MetadataFile metadataFile) internal static MetadataTableTreeNode CreateTableTreeNode(TableIndex table, MetadataFile metadataFile)
{ {

17
ILSpy/Options/OptionsDialog.xaml.cs

@ -29,9 +29,9 @@ namespace ICSharpCode.ILSpy.Options
/// </summary> /// </summary>
public sealed partial class OptionsDialog public sealed partial class OptionsDialog
{ {
public OptionsDialog() public OptionsDialog(SettingsService settingsService)
{ {
DataContext = new OptionsDialogViewModel(); DataContext = new OptionsDialogViewModel(settingsService);
InitializeComponent(); InitializeComponent();
} }
} }
@ -59,19 +59,12 @@ namespace ICSharpCode.ILSpy.Options
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._View), Header = nameof(Resources._Options), MenuCategory = nameof(Resources.Options), MenuOrder = 999)] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._View), Header = nameof(Resources._Options), MenuCategory = nameof(Resources.Options), MenuOrder = 999)]
[Shared] [Shared]
sealed class ShowOptionsCommand : SimpleCommand sealed class ShowOptionsCommand(AssemblyTreeModel assemblyTreeModel, SettingsService settingsService) : SimpleCommand
{ {
private readonly AssemblyTreeModel assemblyTreeModel;
public ShowOptionsCommand(AssemblyTreeModel assemblyTreeModel)
{
this.assemblyTreeModel = assemblyTreeModel;
}
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
OptionsDialog dlg = new() { OptionsDialog dlg = new(settingsService) {
Owner = MainWindow.Instance, Owner = App.Current.MainWindow,
}; };
if (dlg.ShowDialog() == true) if (dlg.ShowDialog() == true)
{ {

4
ILSpy/Options/OptionsDialogViewModel.cs

@ -46,9 +46,9 @@ namespace ICSharpCode.ILSpy.Options
.ExceptNullItems() .ExceptNullItems()
.ToArray(); .ToArray();
public OptionsDialogViewModel() public OptionsDialogViewModel(SettingsService settingsService)
{ {
this.snapshot = SettingsService.Instance.CreateSnapshot(); this.snapshot = settingsService.CreateSnapshot();
foreach (var optionPage in optionPages) foreach (var optionPage in optionPages)
{ {

64
ILSpy/Search/SearchPane.xaml.cs

@ -33,9 +33,11 @@ using System.Windows.Media;
using System.Windows.Threading; using System.Windows.Threading;
using ICSharpCode.ILSpy.AppEnv; using ICSharpCode.ILSpy.AppEnv;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpyX.Abstractions;
using ICSharpCode.ILSpyX.Extensions; using ICSharpCode.ILSpyX.Extensions;
using ICSharpCode.ILSpyX.Search; using ICSharpCode.ILSpyX.Search;
@ -57,13 +59,20 @@ namespace ICSharpCode.ILSpy.Search
RunningSearch currentSearch; RunningSearch currentSearch;
bool runSearchOnNextShow; bool runSearchOnNextShow;
IComparer<SearchResult> resultsComparer; IComparer<SearchResult> resultsComparer;
readonly AssemblyTreeModel assemblyTreeModel;
readonly ITreeNodeFactory treeNodeFactory;
readonly SettingsService settingsService;
public ObservableCollection<SearchResult> Results { get; } = []; public ObservableCollection<SearchResult> Results { get; } = [];
string SearchTerm => searchBox.Text; string SearchTerm => searchBox.Text;
public SearchPane() public SearchPane(AssemblyTreeModel assemblyTreeModel, ITreeNodeFactory treeNodeFactory, SettingsService settingsService)
{ {
this.assemblyTreeModel = assemblyTreeModel;
this.treeNodeFactory = treeNodeFactory;
this.settingsService = settingsService;
InitializeComponent(); InitializeComponent();
ContextMenuProvider.Add(listBox); ContextMenuProvider.Add(listBox);
@ -214,7 +223,7 @@ namespace ICSharpCode.ILSpy.Search
var timer = Stopwatch.StartNew(); var timer = Stopwatch.StartNew();
int resultsAdded = 0; int resultsAdded = 0;
while (Results.Count < MAX_RESULTS && timer.ElapsedMilliseconds < MAX_REFRESH_TIME_MS && currentSearch.resultQueue.TryTake(out var result)) while (Results.Count < MAX_RESULTS && timer.ElapsedMilliseconds < MAX_REFRESH_TIME_MS && currentSearch.ResultQueue.TryTake(out var result))
{ {
Results.InsertSorted(result, resultsComparer); Results.InsertSorted(result, resultsComparer);
++resultsAdded; ++resultsAdded;
@ -243,8 +252,7 @@ namespace ICSharpCode.ILSpy.Search
currentSearch = null; currentSearch = null;
} }
MainWindow mainWindow = MainWindow.Instance; resultsComparer = settingsService.DisplaySettings.SortResults ?
resultsComparer = SettingsService.Instance.DisplaySettings.SortResults ?
SearchResult.ComparerByFitness : SearchResult.ComparerByFitness :
SearchResult.ComparerByName; SearchResult.ComparerByName;
Results.Clear(); Results.Clear();
@ -254,9 +262,12 @@ namespace ICSharpCode.ILSpy.Search
{ {
searchProgressBar.IsIndeterminate = true; searchProgressBar.IsIndeterminate = true;
startedSearch = new(await mainWindow.AssemblyTreeModel.AssemblyList.GetAllAssemblies(), searchTerm, startedSearch = new(await assemblyTreeModel.AssemblyList.GetAllAssemblies(),
(SearchMode)searchModeComboBox.SelectedIndex, mainWindow.AssemblyTreeModel.CurrentLanguage, searchTerm,
SettingsService.Instance.SessionSettings.LanguageSettings.ShowApiLevel); (SearchMode)searchModeComboBox.SelectedIndex,
assemblyTreeModel.CurrentLanguage,
treeNodeFactory,
settingsService);
currentSearch = startedSearch; currentSearch = startedSearch;
await startedSearch.Run(); await startedSearch.Run();
@ -285,15 +296,20 @@ namespace ICSharpCode.ILSpy.Search
readonly SearchMode searchMode; readonly SearchMode searchMode;
readonly Language language; readonly Language language;
readonly ApiVisibility apiVisibility; readonly ApiVisibility apiVisibility;
public readonly IProducerConsumerCollection<SearchResult> resultQueue = new ConcurrentQueue<SearchResult>(); readonly ITreeNodeFactory treeNodeFactory;
readonly SettingsService settingsService;
public IProducerConsumerCollection<SearchResult> ResultQueue { get; } = new ConcurrentQueue<SearchResult>();
public RunningSearch(IList<LoadedAssembly> assemblies, string searchTerm, SearchMode searchMode, public RunningSearch(IList<LoadedAssembly> assemblies, string searchTerm, SearchMode searchMode,
Language language, ApiVisibility apiVisibility) Language language, ITreeNodeFactory treeNodeFactory, SettingsService settingsService)
{ {
this.assemblies = assemblies; this.assemblies = assemblies;
this.language = language; this.language = language;
this.searchMode = searchMode; this.searchMode = searchMode;
this.apiVisibility = apiVisibility; this.apiVisibility = settingsService.SessionSettings.LanguageSettings.ShowApiLevel;
this.treeNodeFactory = treeNodeFactory;
this.settingsService = settingsService;
this.searchRequest = Parse(searchTerm); this.searchRequest = Parse(searchTerm);
} }
@ -454,8 +470,8 @@ namespace ICSharpCode.ILSpy.Search
request.Keywords = keywords.ToArray(); request.Keywords = keywords.ToArray();
request.RegEx = regex; request.RegEx = regex;
request.SearchResultFactory = new SearchResultFactory(language); request.SearchResultFactory = new SearchResultFactory(language);
request.TreeNodeFactory = new TreeNodeFactory(); request.TreeNodeFactory = this.treeNodeFactory;
request.DecompilerSettings = SettingsService.Instance.DecompilerSettings; request.DecompilerSettings = settingsService.DecompilerSettings;
return request; return request;
} }
@ -504,29 +520,29 @@ namespace ICSharpCode.ILSpy.Search
switch (request.Mode) switch (request.Mode)
{ {
case SearchMode.TypeAndMember: case SearchMode.TypeAndMember:
return new MemberSearchStrategy(language, apiVisibility, request, resultQueue); return new MemberSearchStrategy(language, apiVisibility, request, ResultQueue);
case SearchMode.Type: case SearchMode.Type:
return new MemberSearchStrategy(language, apiVisibility, request, resultQueue, MemberSearchKind.Type); return new MemberSearchStrategy(language, apiVisibility, request, ResultQueue, MemberSearchKind.Type);
case SearchMode.Member: case SearchMode.Member:
return new MemberSearchStrategy(language, apiVisibility, request, resultQueue, request.MemberSearchKind); return new MemberSearchStrategy(language, apiVisibility, request, ResultQueue, request.MemberSearchKind);
case SearchMode.Literal: case SearchMode.Literal:
return new LiteralSearchStrategy(language, apiVisibility, request, resultQueue); return new LiteralSearchStrategy(language, apiVisibility, request, ResultQueue);
case SearchMode.Method: case SearchMode.Method:
return new MemberSearchStrategy(language, apiVisibility, request, resultQueue, MemberSearchKind.Method); return new MemberSearchStrategy(language, apiVisibility, request, ResultQueue, MemberSearchKind.Method);
case SearchMode.Field: case SearchMode.Field:
return new MemberSearchStrategy(language, apiVisibility, request, resultQueue, MemberSearchKind.Field); return new MemberSearchStrategy(language, apiVisibility, request, ResultQueue, MemberSearchKind.Field);
case SearchMode.Property: case SearchMode.Property:
return new MemberSearchStrategy(language, apiVisibility, request, resultQueue, MemberSearchKind.Property); return new MemberSearchStrategy(language, apiVisibility, request, ResultQueue, MemberSearchKind.Property);
case SearchMode.Event: case SearchMode.Event:
return new MemberSearchStrategy(language, apiVisibility, request, resultQueue, MemberSearchKind.Event); return new MemberSearchStrategy(language, apiVisibility, request, ResultQueue, MemberSearchKind.Event);
case SearchMode.Token: case SearchMode.Token:
return new MetadataTokenSearchStrategy(language, apiVisibility, request, resultQueue); return new MetadataTokenSearchStrategy(language, apiVisibility, request, ResultQueue);
case SearchMode.Resource: case SearchMode.Resource:
return new ResourceSearchStrategy(apiVisibility, request, resultQueue); return new ResourceSearchStrategy(apiVisibility, request, ResultQueue);
case SearchMode.Assembly: case SearchMode.Assembly:
return new AssemblySearchStrategy(request, resultQueue, AssemblySearchKind.NameOrFileName); return new AssemblySearchStrategy(request, ResultQueue, AssemblySearchKind.NameOrFileName);
case SearchMode.Namespace: case SearchMode.Namespace:
return new NamespaceSearchStrategy(request, resultQueue); return new NamespaceSearchStrategy(request, ResultQueue);
} }
return null; return null;

9
ILSpy/Search/SearchPaneModel.cs

@ -37,11 +37,14 @@ namespace ICSharpCode.ILSpy.Search
[Export] [Export]
public class SearchPaneModel : ToolPaneModel public class SearchPaneModel : ToolPaneModel
{ {
private string searchTerm;
public const string PaneContentId = "searchPane"; public const string PaneContentId = "searchPane";
public SearchPaneModel() private readonly SettingsService settingsService;
private string searchTerm;
public SearchPaneModel(SettingsService settingsService)
{ {
this.settingsService = settingsService;
ContentId = PaneContentId; ContentId = PaneContentId;
Title = Properties.Resources.SearchPane_Search; Title = Properties.Resources.SearchPane_Search;
Icon = "Images/Search"; Icon = "Images/Search";
@ -64,7 +67,7 @@ namespace ICSharpCode.ILSpy.Search
new() { Mode = SearchMode.Namespace, Image = Images.Namespace, Name = "Namespace" } new() { Mode = SearchMode.Namespace, Image = Images.Namespace, Name = "Namespace" }
]; ];
public SessionSettings SessionSettings => SettingsService.Instance.SessionSettings; public SessionSettings SessionSettings => settingsService.SessionSettings;
public string SearchTerm { public string SearchTerm {
get => searchTerm; get => searchTerm;

4
ILSpy/Search/SearchResultFactory.cs

@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using System.Composition;
using System.Windows.Media; using System.Windows.Media;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
@ -158,6 +160,8 @@ namespace ICSharpCode.ILSpy.Search
} }
} }
[Export(typeof(ITreeNodeFactory))]
[Shared]
internal class TreeNodeFactory : ITreeNodeFactory internal class TreeNodeFactory : ITreeNodeFactory
{ {
public ITreeNode Create(Resource resource) public ITreeNode Create(Resource resource)

3
ILSpy/SolutionWriter.cs

@ -30,6 +30,7 @@ using ICSharpCode.Decompiler.Solution;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
@ -213,7 +214,7 @@ namespace ICSharpCode.ILSpy
using (var projectFileWriter = new StreamWriter(projectFileName)) using (var projectFileWriter = new StreamWriter(projectFileName))
{ {
var projectFileOutput = new PlainTextOutput(projectFileWriter); var projectFileOutput = new PlainTextOutput(projectFileWriter);
var options = LanguageService.Instance.CreateDecompilationOptions(DockWorkspace.Instance.ActiveTabPage); var options = DockWorkspace.Instance.ActiveTabPage.CreateDecompilationOptions();
options.FullDecompilation = true; options.FullDecompilation = true;
options.CancellationToken = ct; options.CancellationToken = ct;
options.SaveAsProjectDirectory = targetDirectory; options.SaveAsProjectDirectory = targetDirectory;

2
ILSpy/TaskHelper.cs

@ -197,7 +197,7 @@ namespace ICSharpCode.ILSpy
/// </summary> /// </summary>
public static void HandleExceptions(this Task task) public static void HandleExceptions(this Task task)
{ {
task.Catch<Exception>(exception => MainWindow.Instance.Dispatcher.BeginInvoke(new Action(delegate { task.Catch<Exception>(exception => App.Current.Dispatcher.BeginInvoke(new Action(delegate {
AvalonEditTextOutput output = new(); AvalonEditTextOutput output = new();
output.Write(exception.ToString()); output.Write(exception.ToString());
Docking.DockWorkspace.Instance.ShowText(output); Docking.DockWorkspace.Instance.ShowText(output);

60
ILSpy/TextView/DecompilerTextView.cs

@ -74,6 +74,9 @@ namespace ICSharpCode.ILSpy.TextView
/// </summary> /// </summary>
public sealed partial class DecompilerTextView : UserControl, IHaveState, IProgress<DecompilationProgress> public sealed partial class DecompilerTextView : UserControl, IHaveState, IProgress<DecompilationProgress>
{ {
readonly AssemblyTreeModel assemblyTreeModel;
readonly SettingsService settingsService;
private readonly LanguageService languageService;
readonly ReferenceElementGenerator referenceElementGenerator; readonly ReferenceElementGenerator referenceElementGenerator;
readonly UIElementGenerator uiElementGenerator; readonly UIElementGenerator uiElementGenerator;
readonly List<VisualLineElementGenerator?> activeCustomElementGenerators = new List<VisualLineElementGenerator?>(); readonly List<VisualLineElementGenerator?> activeCustomElementGenerators = new List<VisualLineElementGenerator?>();
@ -94,8 +97,12 @@ namespace ICSharpCode.ILSpy.TextView
readonly List<ITextMarker> localReferenceMarks = new List<ITextMarker>(); readonly List<ITextMarker> localReferenceMarks = new List<ITextMarker>();
#region Constructor #region Constructor
public DecompilerTextView() public DecompilerTextView(TabPageModel tabPage)
{ {
this.assemblyTreeModel = tabPage.AssemblyTreeModel;
this.settingsService = tabPage.SettingsService;
this.languageService = tabPage.LanguageService;
RegisterHighlighting(); RegisterHighlighting();
InitializeComponent(); InitializeComponent();
@ -113,9 +120,9 @@ namespace ICSharpCode.ILSpy.TextView
textEditor.TextArea.Caret.PositionChanged += HighlightBrackets; textEditor.TextArea.Caret.PositionChanged += HighlightBrackets;
textEditor.MouseMove += TextEditorMouseMove; textEditor.MouseMove += TextEditorMouseMove;
textEditor.MouseLeave += TextEditorMouseLeave; textEditor.MouseLeave += TextEditorMouseLeave;
textEditor.SetBinding(Control.FontFamilyProperty, new Binding { Source = SettingsService.Instance.DisplaySettings, Path = new PropertyPath("SelectedFont") }); textEditor.SetBinding(Control.FontFamilyProperty, new Binding { Source = settingsService.DisplaySettings, Path = new PropertyPath("SelectedFont") });
textEditor.SetBinding(Control.FontSizeProperty, new Binding { Source = SettingsService.Instance.DisplaySettings, Path = new PropertyPath("SelectedFontSize") }); textEditor.SetBinding(Control.FontSizeProperty, new Binding { Source = settingsService.DisplaySettings, Path = new PropertyPath("SelectedFontSize") });
textEditor.SetBinding(TextEditor.WordWrapProperty, new Binding { Source = SettingsService.Instance.DisplaySettings, Path = new PropertyPath("EnableWordWrap") }); textEditor.SetBinding(TextEditor.WordWrapProperty, new Binding { Source = settingsService.DisplaySettings, Path = new PropertyPath("EnableWordWrap") });
// disable Tab editing command (useless for read-only editor); allow using tab for focus navigation instead // disable Tab editing command (useless for read-only editor); allow using tab for focus navigation instead
RemoveEditCommand(EditingCommands.TabForward); RemoveEditCommand(EditingCommands.TabForward);
@ -130,7 +137,7 @@ namespace ICSharpCode.ILSpy.TextView
// SearchPanel // SearchPanel
SearchPanel searchPanel = SearchPanel.Install(textEditor.TextArea); SearchPanel searchPanel = SearchPanel.Install(textEditor.TextArea);
searchPanel.RegisterCommands(Application.Current.MainWindow.CommandBindings); searchPanel.RegisterCommands(App.Current.MainWindow.CommandBindings);
searchPanel.SetResourceReference(SearchPanel.MarkerBrushProperty, ResourceKeys.SearchResultBackgroundBrush); searchPanel.SetResourceReference(SearchPanel.MarkerBrushProperty, ResourceKeys.SearchResultBackgroundBrush);
searchPanel.Loaded += (_, _) => { searchPanel.Loaded += (_, _) => {
// HACK: fix search text box // HACK: fix search text box
@ -207,14 +214,14 @@ namespace ICSharpCode.ILSpy.TextView
{ {
if (margin is LineNumberMargin || margin is System.Windows.Shapes.Line) if (margin is LineNumberMargin || margin is System.Windows.Shapes.Line)
{ {
margin.Visibility = SettingsService.Instance.DisplaySettings.ShowLineNumbers ? Visibility.Visible : Visibility.Collapsed; margin.Visibility = settingsService.DisplaySettings.ShowLineNumbers ? Visibility.Visible : Visibility.Collapsed;
} }
} }
} }
void SetHighlightCurrentLine() void SetHighlightCurrentLine()
{ {
textEditor.Options.HighlightCurrentLine = SettingsService.Instance.DisplaySettings.HighlightCurrentLine; textEditor.Options.HighlightCurrentLine = settingsService.DisplaySettings.HighlightCurrentLine;
} }
#endregion #endregion
@ -400,10 +407,12 @@ namespace ICSharpCode.ILSpy.TextView
object? GenerateTooltip(ReferenceSegment segment) object? GenerateTooltip(ReferenceSegment segment)
{ {
var fontSize = settingsService.DisplaySettings.SelectedFontSize;
if (segment.Reference is ICSharpCode.Decompiler.Disassembler.OpCodeInfo code) if (segment.Reference is ICSharpCode.Decompiler.Disassembler.OpCodeInfo code)
{ {
XmlDocumentationProvider docProvider = XmlDocLoader.MscorlibDocumentation; XmlDocumentationProvider docProvider = XmlDocLoader.MscorlibDocumentation;
DocumentationUIBuilder renderer = new DocumentationUIBuilder(new CSharpAmbience(), LanguageService.Instance.Language.SyntaxHighlighting); DocumentationUIBuilder renderer = new DocumentationUIBuilder(new CSharpAmbience(), languageService.Language.SyntaxHighlighting, settingsService.DisplaySettings);
renderer.AddSignatureBlock($"{code.Name} (0x{code.Code:x})"); renderer.AddSignatureBlock($"{code.Name} (0x{code.Code:x})");
if (docProvider != null) if (docProvider != null)
{ {
@ -413,18 +422,18 @@ namespace ICSharpCode.ILSpy.TextView
renderer.AddXmlDocumentation(documentation, null, null); renderer.AddXmlDocumentation(documentation, null, null);
} }
} }
return new FlowDocumentTooltip(renderer.CreateDocument()); return new FlowDocumentTooltip(renderer.CreateDocument(), fontSize);
} }
else if (segment.Reference is IEntity entity) else if (segment.Reference is IEntity entity)
{ {
var document = CreateTooltipForEntity(entity); var document = CreateTooltipForEntity(entity);
if (document == null) if (document == null)
return null; return null;
return new FlowDocumentTooltip(document); return new FlowDocumentTooltip(document, fontSize);
} }
else if (segment.Reference is EntityReference unresolvedEntity) else if (segment.Reference is EntityReference unresolvedEntity)
{ {
var module = unresolvedEntity.ResolveAssembly(MainWindow.Instance.AssemblyTreeModel.AssemblyList); var module = unresolvedEntity.ResolveAssembly(assemblyTreeModel.AssemblyList);
if (module == null) if (module == null)
return null; return null;
var typeSystem = new DecompilerTypeSystem(module, var typeSystem = new DecompilerTypeSystem(module,
@ -441,7 +450,7 @@ namespace ICSharpCode.ILSpy.TextView
var document = CreateTooltipForEntity(resolved); var document = CreateTooltipForEntity(resolved);
if (document == null) if (document == null)
return null; return null;
return new FlowDocumentTooltip(document); return new FlowDocumentTooltip(document, fontSize);
} }
catch (BadImageFormatException) catch (BadImageFormatException)
{ {
@ -451,10 +460,10 @@ namespace ICSharpCode.ILSpy.TextView
return null; return null;
} }
static FlowDocument? CreateTooltipForEntity(IEntity resolved) FlowDocument? CreateTooltipForEntity(IEntity resolved)
{ {
Language currentLanguage = LanguageService.Instance.Language; Language currentLanguage = languageService.Language;
DocumentationUIBuilder renderer = new DocumentationUIBuilder(new CSharpAmbience(), currentLanguage.SyntaxHighlighting); DocumentationUIBuilder renderer = new DocumentationUIBuilder(new CSharpAmbience(), currentLanguage.SyntaxHighlighting, settingsService.DisplaySettings);
RichText richText = currentLanguage.GetRichTextTooltip(resolved); RichText richText = currentLanguage.GetRichTextTooltip(resolved);
if (richText == null) if (richText == null)
{ {
@ -484,7 +493,7 @@ namespace ICSharpCode.ILSpy.TextView
IEntity? ResolveReference(string idString) IEntity? ResolveReference(string idString)
{ {
return AssemblyTreeModel.FindEntityInRelevantAssemblies(idString, MainWindow.Instance.AssemblyTreeModel.AssemblyList.GetAssemblies()); return AssemblyTreeModel.FindEntityInRelevantAssemblies(idString, assemblyTreeModel.AssemblyList.GetAssemblies());
} }
} }
@ -492,13 +501,12 @@ namespace ICSharpCode.ILSpy.TextView
{ {
readonly FlowDocumentScrollViewer viewer; readonly FlowDocumentScrollViewer viewer;
public FlowDocumentTooltip(FlowDocument document) public FlowDocumentTooltip(FlowDocument document, double fontSize)
{ {
TextOptions.SetTextFormattingMode(this, TextFormattingMode.Display); TextOptions.SetTextFormattingMode(this, TextFormattingMode.Display);
double fontSize = SettingsService.Instance.DisplaySettings.SelectedFontSize;
viewer = new FlowDocumentScrollViewer() { viewer = new FlowDocumentScrollViewer() {
Width = document.MinPageWidth + fontSize * 5, Width = document.MinPageWidth + fontSize * 5,
MaxWidth = MainWindow.Instance.ActualWidth MaxWidth = App.Current.MainWindow.ActualWidth
}; };
viewer.Document = document; viewer.Document = document;
Border border = new Border { Border border = new Border {
@ -542,9 +550,9 @@ namespace ICSharpCode.ILSpy.TextView
#region Highlight brackets #region Highlight brackets
void HighlightBrackets(object? sender, EventArgs e) void HighlightBrackets(object? sender, EventArgs e)
{ {
if (SettingsService.Instance.DisplaySettings.HighlightMatchingBraces) if (settingsService.DisplaySettings.HighlightMatchingBraces)
{ {
var result = LanguageService.Instance.Language.BracketSearcher.SearchBracket(textEditor.Document, textEditor.CaretOffset); var result = languageService.Language.BracketSearcher.SearchBracket(textEditor.Document, textEditor.CaretOffset);
bracketHighlightRenderer.SetHighlight(result); bracketHighlightRenderer.SetHighlight(result);
} }
else else
@ -564,7 +572,7 @@ namespace ICSharpCode.ILSpy.TextView
progressTitle.Text = !string.IsNullOrWhiteSpace(value.Title) ? value.Title : Properties.Resources.Decompiling; progressTitle.Text = !string.IsNullOrWhiteSpace(value.Title) ? value.Title : Properties.Resources.Decompiling;
progressText.Text = value.Status; progressText.Text = value.Status;
progressText.Visibility = !string.IsNullOrWhiteSpace(progressText.Text) ? Visibility.Visible : Visibility.Collapsed; progressText.Visibility = !string.IsNullOrWhiteSpace(progressText.Text) ? Visibility.Visible : Visibility.Collapsed;
var taskBar = MainWindow.Instance.TaskbarItemInfo; var taskBar = App.Current.MainWindow.TaskbarItemInfo;
if (taskBar != null) if (taskBar != null)
{ {
taskBar.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Normal; taskBar.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Normal;
@ -594,7 +602,7 @@ namespace ICSharpCode.ILSpy.TextView
progressText.Text = null; progressText.Text = null;
progressText.Visibility = Visibility.Collapsed; progressText.Visibility = Visibility.Collapsed;
waitAdorner.BeginAnimation(OpacityProperty, new DoubleAnimation(0, 1, new Duration(TimeSpan.FromSeconds(0.5)), FillBehavior.Stop)); waitAdorner.BeginAnimation(OpacityProperty, new DoubleAnimation(0, 1, new Duration(TimeSpan.FromSeconds(0.5)), FillBehavior.Stop));
var taskBar = MainWindow.Instance.TaskbarItemInfo; var taskBar = App.Current.MainWindow.TaskbarItemInfo;
if (taskBar != null) if (taskBar != null)
{ {
taskBar.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Indeterminate; taskBar.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Indeterminate;
@ -633,7 +641,7 @@ namespace ICSharpCode.ILSpy.TextView
progressBar.IsIndeterminate = false; progressBar.IsIndeterminate = false;
progressText.Text = null; progressText.Text = null;
progressText.Visibility = Visibility.Collapsed; progressText.Visibility = Visibility.Collapsed;
var taskBar = MainWindow.Instance.TaskbarItemInfo; var taskBar = App.Current.MainWindow.TaskbarItemInfo;
if (taskBar != null) if (taskBar != null)
{ {
taskBar.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None; taskBar.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
@ -764,7 +772,7 @@ namespace ICSharpCode.ILSpy.TextView
{ {
if (state != null) if (state != null)
{ {
state.RestoreFoldings(textOutput.Foldings, SettingsService.Instance.DisplaySettings.ExpandMemberDefinitions); state.RestoreFoldings(textOutput.Foldings, settingsService.DisplaySettings.ExpandMemberDefinitions);
textEditor.ScrollToVerticalOffset(state.VerticalOffset); textEditor.ScrollToVerticalOffset(state.VerticalOffset);
textEditor.ScrollToHorizontalOffset(state.HorizontalOffset); textEditor.ScrollToHorizontalOffset(state.HorizontalOffset);
} }
@ -788,7 +796,7 @@ namespace ICSharpCode.ILSpy.TextView
} }
currentAddress = textOutput.Address; currentAddress = textOutput.Address;
currentTitle = textOutput.Title; currentTitle = textOutput.Title;
expandMemberDefinitions = SettingsService.Instance.DisplaySettings.ExpandMemberDefinitions; expandMemberDefinitions = settingsService.DisplaySettings.ExpandMemberDefinitions;
} }
#endregion #endregion

13
ILSpy/TextView/DocumentationUIBuilder.cs

@ -19,15 +19,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Media; using System.Windows.Media;
using System.Xml;
using System.Xml.Linq; using System.Xml.Linq;
using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Document;
@ -47,14 +44,16 @@ namespace ICSharpCode.ILSpy.TextView
{ {
readonly IAmbience ambience; readonly IAmbience ambience;
readonly IHighlightingDefinition highlightingDefinition; readonly IHighlightingDefinition highlightingDefinition;
readonly DisplaySettings displaySettings;
readonly FlowDocument document; readonly FlowDocument document;
BlockCollection blockCollection; BlockCollection blockCollection;
InlineCollection inlineCollection; InlineCollection inlineCollection;
public DocumentationUIBuilder(IAmbience ambience, IHighlightingDefinition highlightingDefinition) public DocumentationUIBuilder(IAmbience ambience, IHighlightingDefinition highlightingDefinition, DisplaySettings displaySettings)
{ {
this.ambience = ambience; this.ambience = ambience;
this.highlightingDefinition = highlightingDefinition; this.highlightingDefinition = highlightingDefinition;
this.displaySettings = displaySettings;
this.document = new FlowDocument(); this.document = new FlowDocument();
this.blockCollection = document.Blocks; this.blockCollection = document.Blocks;
@ -115,12 +114,12 @@ namespace ICSharpCode.ILSpy.TextView
// Paragraph sadly does not support TextWrapping.NoWrap // Paragraph sadly does not support TextWrapping.NoWrap
var text = new TextBlock { var text = new TextBlock {
FontFamily = GetCodeFont(), FontFamily = GetCodeFont(),
FontSize = SettingsService.Instance.DisplaySettings.SelectedFontSize, FontSize = displaySettings.SelectedFontSize,
TextAlignment = TextAlignment.Left TextAlignment = TextAlignment.Left
}; };
text.Inlines.AddRange(richText.CreateRuns(document)); text.Inlines.AddRange(richText.CreateRuns(document));
text.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); text.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
this.document.MinPageWidth = Math.Min(text.DesiredSize.Width, MainWindow.Instance.ActualWidth); this.document.MinPageWidth = Math.Min(text.DesiredSize.Width, App.Current.MainWindow.ActualWidth);
block.Inlines.AddRange(richText.CreateRuns(document)); block.Inlines.AddRange(richText.CreateRuns(document));
block.FontFamily = GetCodeFont(); block.FontFamily = GetCodeFont();
block.TextAlignment = TextAlignment.Left; block.TextAlignment = TextAlignment.Left;
@ -435,7 +434,7 @@ namespace ICSharpCode.ILSpy.TextView
FontFamily GetCodeFont() FontFamily GetCodeFont()
{ {
return SettingsService.Instance.DisplaySettings.SelectedFont; return displaySettings.SelectedFont;
} }
public void AddInline(Inline inline) public void AddInline(Inline inline)

32
ILSpy/Themes/WindowStyleManagerBehavior.cs

@ -27,6 +27,7 @@ using ICSharpCode.ILSpy.Options;
using TomsToolbox.Essentials; using TomsToolbox.Essentials;
using TomsToolbox.Wpf; using TomsToolbox.Wpf;
using TomsToolbox.Wpf.Composition;
using TomsToolbox.Wpf.Interactivity; using TomsToolbox.Wpf.Interactivity;
namespace ICSharpCode.ILSpy.Themes namespace ICSharpCode.ILSpy.Themes
@ -42,7 +43,7 @@ namespace ICSharpCode.ILSpy.Themes
{ {
base.OnAttached(); base.OnAttached();
SettingsService.Instance.DisplaySettings.PropertyChanged += DisplaySettings_PropertyChanged; MessageBus<SettingsChangedEventArgs>.Subscribers += (sender, e) => DisplaySettings_PropertyChanged(sender, e);
_foreground = AssociatedObject.Track(Control.ForegroundProperty); _foreground = AssociatedObject.Track(Control.ForegroundProperty);
_background = AssociatedObject.Track(Control.BackgroundProperty); _background = AssociatedObject.Track(Control.BackgroundProperty);
@ -50,7 +51,7 @@ namespace ICSharpCode.ILSpy.Themes
_foreground.Changed += Color_Changed; _foreground.Changed += Color_Changed;
_background.Changed += Color_Changed; _background.Changed += Color_Changed;
UpdateWindowStyle(); UpdateWindowStyle(AssociatedObject.GetExportProvider().GetExportedValue<SettingsService>().DisplaySettings);
ApplyThemeToWindowCaption(); ApplyThemeToWindowCaption();
} }
@ -60,8 +61,6 @@ namespace ICSharpCode.ILSpy.Themes
_foreground.Changed -= Color_Changed; _foreground.Changed -= Color_Changed;
_background.Changed -= Color_Changed; _background.Changed -= Color_Changed;
SettingsService.Instance.DisplaySettings.PropertyChanged -= DisplaySettings_PropertyChanged;
} }
private void Color_Changed(object sender, EventArgs e) private void Color_Changed(object sender, EventArgs e)
@ -69,12 +68,14 @@ namespace ICSharpCode.ILSpy.Themes
ApplyThemeToWindowCaption(); ApplyThemeToWindowCaption();
} }
private void UpdateWindowStyle() private void UpdateWindowStyle(DisplaySettings displaySettings)
{ {
var window = AssociatedObject; var window = AssociatedObject;
if (SettingsService.Instance.DisplaySettings.StyleWindowTitleBar) if (displaySettings.StyleWindowTitleBar)
{
window.Style = (Style)window.FindResource(TomsToolbox.Wpf.Styles.ResourceKeys.WindowStyle); window.Style = (Style)window.FindResource(TomsToolbox.Wpf.Styles.ResourceKeys.WindowStyle);
}
} }
private static void ShowRestartNotification() private static void ShowRestartNotification()
@ -84,16 +85,19 @@ namespace ICSharpCode.ILSpy.Themes
private void DisplaySettings_PropertyChanged(object sender, PropertyChangedEventArgs e) private void DisplaySettings_PropertyChanged(object sender, PropertyChangedEventArgs e)
{ {
if (e.PropertyName == nameof(DisplaySettings.StyleWindowTitleBar)) if (sender is not DisplaySettings displaySettings)
{ return;
if (!SettingsService.Instance.DisplaySettings.StyleWindowTitleBar)
{ if (e.PropertyName != nameof(DisplaySettings.StyleWindowTitleBar))
restartNotificationThrottle.Tick(); return;
return;
}
UpdateWindowStyle(); if (!displaySettings.StyleWindowTitleBar)
{
restartNotificationThrottle.Tick();
return;
} }
UpdateWindowStyle(displaySettings);
} }
private void ApplyThemeToWindowCaption() private void ApplyThemeToWindowCaption()

11
ILSpy/TreeNodes/AssemblyListTreeNode.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
@ -25,6 +26,7 @@ using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpyX.TreeView; using ICSharpCode.ILSpyX.TreeView;
using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions; using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions;
@ -45,7 +47,10 @@ namespace ICSharpCode.ILSpy.TreeNodes
public AssemblyListTreeNode(AssemblyList assemblyList) public AssemblyListTreeNode(AssemblyList assemblyList)
{ {
this.assemblyList = assemblyList ?? throw new ArgumentNullException(nameof(assemblyList)); ArgumentNullException.ThrowIfNull(assemblyList);
this.assemblyList = assemblyList;
BindToObservableCollection(assemblyList); BindToObservableCollection(assemblyList);
} }
@ -107,8 +112,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
.Distinct() .Distinct()
.ToArray(); .ToArray();
assemblyList.Move(assemblies, index); assemblyList.Move(assemblies, index);
var nodes = assemblies.SelectArray(MainWindow.Instance.AssemblyTreeModel.FindTreeNode); var nodes = assemblies.SelectArray(AssemblyTreeModel.FindTreeNode);
MainWindow.Instance.AssemblyTreeModel.SelectNodes(nodes); AssemblyTreeModel.SelectNodes(nodes);
} }
} }

4
ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs

@ -85,11 +85,11 @@ namespace ICSharpCode.ILSpy.TreeNodes
{ {
this.Children.Add(new AssemblyReferenceReferencedTypesTreeNode(module, r)); this.Children.Add(new AssemblyReferenceReferencedTypesTreeNode(module, r));
var resolver = parentAssembly.LoadedAssembly.GetAssemblyResolver(SettingsService.Instance.DecompilerSettings.AutoLoadAssemblyReferences); var resolver = parentAssembly.LoadedAssembly.GetAssemblyResolver(SettingsService.DecompilerSettings.AutoLoadAssemblyReferences);
var referencedModule = resolver.Resolve(r); var referencedModule = resolver.Resolve(r);
if (referencedModule != null) if (referencedModule != null)
{ {
var module = (MetadataModule)referencedModule.GetTypeSystemWithCurrentOptionsOrNull().MainModule; var module = (MetadataModule)referencedModule.GetTypeSystemWithCurrentOptionsOrNull(SettingsService)?.MainModule;
foreach (var childRef in referencedModule.AssemblyReferences) foreach (var childRef in referencedModule.AssemblyReferences)
this.Children.Add(new AssemblyReferenceTreeNode(module, childRef, parentAssembly)); this.Children.Add(new AssemblyReferenceTreeNode(module, childRef, parentAssembly));
} }

21
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -263,7 +263,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
ns.Children.Clear(); ns.Children.Clear();
} }
namespaces.Clear(); namespaces.Clear();
bool useNestedStructure = SettingsService.Instance.DisplaySettings.UseNestedNamespaceNodes; bool useNestedStructure = SettingsService.DisplaySettings.UseNestedNamespaceNodes;
foreach (var type in assembly.TopLevelTypeDefinitions.OrderBy(t => t.ReflectionName, NaturalStringComparer.Instance)) foreach (var type in assembly.TopLevelTypeDefinitions.OrderBy(t => t.ReflectionName, NaturalStringComparer.Instance))
{ {
var ns = GetOrCreateNamespaceTreeNode(type.Namespace); var ns = GetOrCreateNamespaceTreeNode(type.Namespace);
@ -329,7 +329,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
ns.Children.Clear(); ns.Children.Clear();
} }
namespaces.Clear(); namespaces.Clear();
bool useNestedStructure = SettingsService.Instance.DisplaySettings.UseNestedNamespaceNodes; bool useNestedStructure = SettingsService.DisplaySettings.UseNestedNamespaceNodes;
foreach (var type in assembly.TopLevelTypeDefinitions.OrderBy(t => t.ReflectionName, NaturalStringComparer.Instance)) foreach (var type in assembly.TopLevelTypeDefinitions.OrderBy(t => t.ReflectionName, NaturalStringComparer.Instance))
{ {
var ns = GetOrCreateNamespaceTreeNode(type.Namespace); var ns = GetOrCreateNamespaceTreeNode(type.Namespace);
@ -547,7 +547,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
dlg.Filter = language.Name + " project|*" + language.ProjectFileExtension + "|" + language.Name + " single file|*" + language.FileExtension + "|All files|*.*"; dlg.Filter = language.Name + " project|*" + language.ProjectFileExtension + "|" + language.Name + " single file|*" + language.FileExtension + "|All files|*.*";
if (dlg.ShowDialog() == true) if (dlg.ShowDialog() == true)
{ {
var options = LanguageService.Instance.CreateDecompilationOptions(DockWorkspace.Instance.ActiveTabPage); var options = DockWorkspace.Instance.ActiveTabPage.CreateDecompilationOptions();
options.FullDecompilation = true; options.FullDecompilation = true;
if (dlg.FilterIndex == 1) if (dlg.FilterIndex == 1)
{ {
@ -608,7 +608,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
[ExportContextMenuEntry(Header = nameof(Resources._Reload), Icon = "images/Refresh")] [ExportContextMenuEntry(Header = nameof(Resources._Reload), Icon = "images/Refresh")]
[Shared] [Shared]
sealed class ReloadAssembly : IContextMenuEntry sealed class ReloadAssembly(AssemblyTreeModel assemblyTreeModel) : IContextMenuEntry
{ {
public bool IsVisible(TextViewContext context) public bool IsVisible(TextViewContext context)
{ {
@ -636,14 +636,14 @@ namespace ICSharpCode.ILSpy.TreeNodes
la.AssemblyList.ReloadAssembly(la.FileName); la.AssemblyList.ReloadAssembly(la.FileName);
} }
} }
MainWindow.Instance.AssemblyTreeModel.SelectNodes(paths.Select(p => MainWindow.Instance.AssemblyTreeModel.FindNodeByPath(p, true)).ToArray()); assemblyTreeModel.SelectNodes(paths.Select(p => assemblyTreeModel.FindNodeByPath(p, true)).ToArray());
MainWindow.Instance.AssemblyTreeModel.RefreshDecompiledView(); assemblyTreeModel.RefreshDecompiledView();
} }
} }
[ExportContextMenuEntry(Header = nameof(Resources._LoadDependencies), Category = nameof(Resources.Dependencies))] [ExportContextMenuEntry(Header = nameof(Resources._LoadDependencies), Category = nameof(Resources.Dependencies))]
[Shared] [Shared]
sealed class LoadDependencies : IContextMenuEntry sealed class LoadDependencies(AssemblyTreeModel assemblyTreeModel) : IContextMenuEntry
{ {
public bool IsVisible(TextViewContext context) public bool IsVisible(TextViewContext context)
{ {
@ -677,13 +677,13 @@ namespace ICSharpCode.ILSpy.TreeNodes
} }
} }
await Task.WhenAll(tasks); await Task.WhenAll(tasks);
MainWindow.Instance.AssemblyTreeModel.RefreshDecompiledView(); assemblyTreeModel.RefreshDecompiledView();
} }
} }
[ExportContextMenuEntry(Header = nameof(Resources._AddMainList), Category = nameof(Resources.Dependencies))] [ExportContextMenuEntry(Header = nameof(Resources._AddMainList), Category = nameof(Resources.Dependencies))]
[Shared] [Shared]
sealed class AddToMainList : IContextMenuEntry sealed class AddToMainList(AssemblyTreeModel assemblyTreeModel) : IContextMenuEntry
{ {
public bool IsVisible(TextViewContext context) public bool IsVisible(TextViewContext context)
{ {
@ -712,7 +712,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
node.RaisePropertyChanged(nameof(ILSpyTreeNode.IsAutoLoaded)); node.RaisePropertyChanged(nameof(ILSpyTreeNode.IsAutoLoaded));
} }
} }
MainWindow.Instance.AssemblyTreeModel.AssemblyList.RefreshSave();
assemblyTreeModel.AssemblyList.RefreshSave();
} }
} }

2
ILSpy/TreeNodes/DerivedTypesEntryNode.cs

@ -55,7 +55,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
return FilterResult.Hidden; return FilterResult.Hidden;
if (settings.SearchTermMatches(type.Name)) if (settings.SearchTermMatches(type.Name))
{ {
if (type.DeclaringType != null && (settings.ShowApiLevel != ApiVisibility.All || !LanguageService.Instance.Language.ShowMember(type))) if (type.DeclaringType != null && (settings.ShowApiLevel != ApiVisibility.All || !LanguageService.Language.ShowMember(type)))
return FilterResult.Hidden; return FilterResult.Hidden;
else else
return FilterResult.Match; return FilterResult.Match;

6
ILSpy/TreeNodes/EventTreeNode.cs

@ -51,8 +51,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
private IEvent GetEventDefinition() private IEvent GetEventDefinition()
{ {
return ((MetadataModule)EventDefinition.ParentModule.MetadataFile return ((MetadataModule)EventDefinition.ParentModule?.MetadataFile
?.GetTypeSystemWithCurrentOptionsOrNull() ?.GetTypeSystemWithCurrentOptionsOrNull(SettingsService)
?.MainModule)?.GetDefinition((EventDefinitionHandle)EventDefinition.MetadataToken) ?? EventDefinition; ?.MainModule)?.GetDefinition((EventDefinitionHandle)EventDefinition.MetadataToken) ?? EventDefinition;
} }
@ -72,7 +72,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
{ {
if (settings.ShowApiLevel == ApiVisibility.PublicOnly && !IsPublicAPI) if (settings.ShowApiLevel == ApiVisibility.PublicOnly && !IsPublicAPI)
return FilterResult.Hidden; return FilterResult.Hidden;
if (settings.SearchTermMatches(EventDefinition.Name) && (settings.ShowApiLevel == ApiVisibility.All || LanguageService.Instance.Language.ShowMember(EventDefinition))) if (settings.SearchTermMatches(EventDefinition.Name) && (settings.ShowApiLevel == ApiVisibility.All || LanguageService.Language.ShowMember(EventDefinition)))
return FilterResult.Match; return FilterResult.Match;
else else
return FilterResult.Hidden; return FilterResult.Hidden;

6
ILSpy/TreeNodes/FieldTreeNode.cs

@ -43,8 +43,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
private IField GetFieldDefinition() private IField GetFieldDefinition()
{ {
return ((MetadataModule)FieldDefinition.ParentModule.MetadataFile return ((MetadataModule)FieldDefinition.ParentModule?.MetadataFile
?.GetTypeSystemWithCurrentOptionsOrNull() ?.GetTypeSystemWithCurrentOptionsOrNull(SettingsService)
?.MainModule)?.GetDefinition((FieldDefinitionHandle)FieldDefinition.MetadataToken) ?? FieldDefinition; ?.MainModule)?.GetDefinition((FieldDefinitionHandle)FieldDefinition.MetadataToken) ?? FieldDefinition;
} }
@ -73,7 +73,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
{ {
if (settings.ShowApiLevel == ApiVisibility.PublicOnly && !IsPublicAPI) if (settings.ShowApiLevel == ApiVisibility.PublicOnly && !IsPublicAPI)
return FilterResult.Hidden; return FilterResult.Hidden;
if (settings.SearchTermMatches(FieldDefinition.Name) && (settings.ShowApiLevel == ApiVisibility.All || LanguageService.Instance.Language.ShowMember(FieldDefinition))) if (settings.SearchTermMatches(FieldDefinition.Name) && (settings.ShowApiLevel == ApiVisibility.All || LanguageService.Language.ShowMember(FieldDefinition)))
return FilterResult.Match; return FilterResult.Match;
else else
return FilterResult.Hidden; return FilterResult.Hidden;

28
ILSpy/TreeNodes/ILSpyTreeNode.cs

@ -16,7 +16,6 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;
@ -27,6 +26,7 @@ using System.Windows.Threading;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpyX.Abstractions; using ICSharpCode.ILSpyX.Abstractions;
using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions; using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions;
using ICSharpCode.ILSpyX.TreeView; using ICSharpCode.ILSpyX.TreeView;
@ -45,9 +45,17 @@ namespace ICSharpCode.ILSpy.TreeNodes
MessageBus<SettingsChangedEventArgs>.Subscribers += (sender, e) => Settings_Changed(sender, e); MessageBus<SettingsChangedEventArgs>.Subscribers += (sender, e) => Settings_Changed(sender, e);
} }
LanguageSettings LanguageSettings => SettingsService.Instance.SessionSettings.LanguageSettings; LanguageSettings LanguageSettings => SettingsService.SessionSettings.LanguageSettings;
public Language Language => LanguageService.Instance.Language; public Language Language => LanguageService.Language;
public static AssemblyTreeModel AssemblyTreeModel { get; } = App.ExportProvider.GetExportedValue<AssemblyTreeModel>();
public static ICollection<IResourceNodeFactory> ResourceNodeFactories { get; } = App.ExportProvider.GetExportedValues<IResourceNodeFactory>().ToArray();
public static SettingsService SettingsService { get; } = App.ExportProvider.GetExportedValue<SettingsService>();
public static LanguageService LanguageService { get; } = App.ExportProvider.GetExportedValue<LanguageService>();
public virtual FilterResult Filter(LanguageSettings settings) public virtual FilterResult Filter(LanguageSettings settings)
{ {
@ -71,8 +79,11 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override void ActivateItemSecondary(IPlatformRoutedEventArgs e) public override void ActivateItemSecondary(IPlatformRoutedEventArgs e)
{ {
MainWindow.Instance.AssemblyTreeModel.SelectNode(this, inNewTabPage: true); var assemblyTreeModel = AssemblyTreeModel;
MainWindow.Instance.Dispatcher.BeginInvoke(DispatcherPriority.Background, (Action)MainWindow.Instance.AssemblyTreeModel.RefreshDecompiledView);
assemblyTreeModel.SelectNode(this, inNewTabPage: true);
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, assemblyTreeModel.RefreshDecompiledView);
} }
/// <summary> /// <summary>
@ -87,6 +98,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override void OnChildrenChanged(NotifyCollectionChangedEventArgs e) public override void OnChildrenChanged(NotifyCollectionChangedEventArgs e)
{ {
base.OnChildrenChanged(e);
if (e.NewItems != null) if (e.NewItems != null)
{ {
if (IsVisible) if (IsVisible)
@ -99,7 +112,6 @@ namespace ICSharpCode.ILSpy.TreeNodes
childrenNeedFiltering = true; childrenNeedFiltering = true;
} }
} }
base.OnChildrenChanged(e);
} }
void ApplyFilterToChild(ILSpyTreeNode child) void ApplyFilterToChild(ILSpyTreeNode child)
@ -162,11 +174,11 @@ namespace ICSharpCode.ILSpy.TreeNodes
protected string GetSuffixString(EntityHandle handle) protected string GetSuffixString(EntityHandle handle)
{ {
if (!SettingsService.Instance.DisplaySettings.ShowMetadataTokens) if (!SettingsService.DisplaySettings.ShowMetadataTokens)
return string.Empty; return string.Empty;
int token = MetadataTokens.GetToken(handle); int token = MetadataTokens.GetToken(handle);
if (SettingsService.Instance.DisplaySettings.ShowMetadataTokensInBase10) if (SettingsService.DisplaySettings.ShowMetadataTokensInBase10)
return " @" + token; return " @" + token;
return " @" + token.ToString("x8"); return " @" + token.ToString("x8");
} }

8
ILSpy/TreeNodes/MethodTreeNode.cs

@ -43,8 +43,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
private IMethod GetMethodDefinition() private IMethod GetMethodDefinition()
{ {
return ((MetadataModule)MethodDefinition.ParentModule.MetadataFile return ((MetadataModule)MethodDefinition.ParentModule?.MetadataFile
?.GetTypeSystemWithCurrentOptionsOrNull() ?.GetTypeSystemWithCurrentOptionsOrNull(SettingsService)
?.MainModule)?.GetDefinition((MethodDefinitionHandle)MethodDefinition.MetadataToken) ?? MethodDefinition; ?.MainModule)?.GetDefinition((MethodDefinitionHandle)MethodDefinition.MetadataToken) ?? MethodDefinition;
} }
@ -103,7 +103,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
{ {
if (settings.ShowApiLevel == ApiVisibility.PublicOnly && !IsPublicAPI) if (settings.ShowApiLevel == ApiVisibility.PublicOnly && !IsPublicAPI)
return FilterResult.Hidden; return FilterResult.Hidden;
if (settings.SearchTermMatches(MethodDefinition.Name) && (settings.ShowApiLevel == ApiVisibility.All || LanguageService.Instance.Language.ShowMember(MethodDefinition))) if (settings.SearchTermMatches(MethodDefinition.Name) && (settings.ShowApiLevel == ApiVisibility.All || LanguageService.Language.ShowMember(MethodDefinition)))
return FilterResult.Match; return FilterResult.Match;
else else
return FilterResult.Hidden; return FilterResult.Hidden;
@ -127,7 +127,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override string ToString() public override string ToString()
{ {
return LanguageService.Instance.ILLanguage.MethodToString(MethodDefinition, false, false, false); return LanguageService.ILLanguage.MethodToString(MethodDefinition, false, false, false);
} }
} }
} }

8
ILSpy/TreeNodes/PropertyTreeNode.cs

@ -53,8 +53,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
private IProperty GetPropertyDefinition() private IProperty GetPropertyDefinition()
{ {
return ((MetadataModule)PropertyDefinition.ParentModule.MetadataFile return ((MetadataModule)PropertyDefinition.ParentModule?.MetadataFile
?.GetTypeSystemWithCurrentOptionsOrNull() ?.GetTypeSystemWithCurrentOptionsOrNull(SettingsService)
?.MainModule)?.GetDefinition((PropertyDefinitionHandle)PropertyDefinition.MetadataToken) ?? PropertyDefinition; ?.MainModule)?.GetDefinition((PropertyDefinitionHandle)PropertyDefinition.MetadataToken) ?? PropertyDefinition;
} }
@ -75,7 +75,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
{ {
if (settings.ShowApiLevel == ApiVisibility.PublicOnly && !IsPublicAPI) if (settings.ShowApiLevel == ApiVisibility.PublicOnly && !IsPublicAPI)
return FilterResult.Hidden; return FilterResult.Hidden;
if (settings.SearchTermMatches(PropertyDefinition.Name) && (settings.ShowApiLevel == ApiVisibility.All || LanguageService.Instance.Language.ShowMember(PropertyDefinition))) if (settings.SearchTermMatches(PropertyDefinition.Name) && (settings.ShowApiLevel == ApiVisibility.All || LanguageService.Language.ShowMember(PropertyDefinition)))
return FilterResult.Match; return FilterResult.Match;
else else
return FilterResult.Hidden; return FilterResult.Hidden;
@ -104,7 +104,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override string ToString() public override string ToString()
{ {
return LanguageService.Instance.ILLanguage.PropertyToString(PropertyDefinition, false, false, false); return LanguageService.ILLanguage.PropertyToString(PropertyDefinition, false, false, false);
} }
} }
} }

2
ILSpy/TreeNodes/ReferenceFolderTreeNode.cs

@ -49,7 +49,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
protected override void LoadChildren() protected override void LoadChildren()
{ {
var metadata = module.Metadata; var metadata = module.Metadata;
var metadataModule = (MetadataModule)module.GetTypeSystemWithCurrentOptionsOrNull().MainModule; var metadataModule = (MetadataModule)module.GetTypeSystemWithCurrentOptionsOrNull(SettingsService)?.MainModule;
foreach (var r in module.AssemblyReferences.OrderBy(r => r.Name)) foreach (var r in module.AssemblyReferences.OrderBy(r => r.Name))
this.Children.Add(new AssemblyReferenceTreeNode(metadataModule, r, parentAssembly)); this.Children.Add(new AssemblyReferenceTreeNode(metadataModule, r, parentAssembly));
foreach (var r in metadata.GetModuleReferences().OrderBy(r => metadata.GetString(metadata.GetModuleReference(r).Name))) foreach (var r in metadata.GetModuleReferences().OrderBy(r => metadata.GetString(metadata.GetModuleReference(r).Name)))

3
ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs

@ -22,7 +22,6 @@ using System.IO;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler; using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpyX.Abstractions;
using Microsoft.Win32; using Microsoft.Win32;
@ -58,7 +57,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public static ILSpyTreeNode Create(Resource resource) public static ILSpyTreeNode Create(Resource resource)
{ {
ILSpyTreeNode result = null; ILSpyTreeNode result = null;
foreach (var factory in App.ExportProvider.GetExportedValues<IResourceNodeFactory>()) foreach (var factory in ResourceNodeFactories)
{ {
result = factory.CreateNode(resource) as ILSpyTreeNode; result = factory.CreateNode(resource) as ILSpyTreeNode;
if (result != null) if (result != null)

6
ILSpy/TreeNodes/TypeTreeNode.cs

@ -49,8 +49,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
{ {
return ((MetadataModule)ParentAssemblyNode.LoadedAssembly return ((MetadataModule)ParentAssemblyNode.LoadedAssembly
.GetMetadataFileOrNull() .GetMetadataFileOrNull()
?.GetTypeSystemWithCurrentOptionsOrNull() ?.GetTypeSystemWithCurrentOptionsOrNull(SettingsService)
?.MainModule).GetDefinition((SRM.TypeDefinitionHandle)TypeDefinition.MetadataToken); ?.MainModule)?.GetDefinition((SRM.TypeDefinitionHandle)TypeDefinition.MetadataToken);
} }
public override bool IsPublicAPI { public override bool IsPublicAPI {
@ -73,7 +73,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
return FilterResult.Hidden; return FilterResult.Hidden;
if (settings.SearchTermMatches(TypeDefinition.Name)) if (settings.SearchTermMatches(TypeDefinition.Name))
{ {
if (settings.ShowApiLevel == ApiVisibility.All || LanguageService.Instance.Language.ShowMember(TypeDefinition)) if (settings.ShowApiLevel == ApiVisibility.All || LanguageService.Language.ShowMember(TypeDefinition))
return FilterResult.Match; return FilterResult.Match;
else else
return FilterResult.Hidden; return FilterResult.Hidden;

15
ILSpy/Util/MenuService.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System.Collections.Generic; using System.Collections.Generic;
using System.Composition;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
@ -35,10 +36,10 @@ using TomsToolbox.Wpf.Converters;
namespace ICSharpCode.ILSpy.Util namespace ICSharpCode.ILSpy.Util
{ {
internal class MenuService [Export]
[Shared]
public class MenuService(IExportProvider exportProvider)
{ {
public static readonly MenuService Instance = new();
private readonly DockWorkspace dockWorkspace = DockWorkspace.Instance; private readonly DockWorkspace dockWorkspace = DockWorkspace.Instance;
public void Init(Menu mainMenu, ToolBar toolBar, InputBindingCollection inputBindings) public void Init(Menu mainMenu, ToolBar toolBar, InputBindingCollection inputBindings)
@ -48,9 +49,9 @@ namespace ICSharpCode.ILSpy.Util
InitToolbar(toolBar); InitToolbar(toolBar);
} }
static void InitMainMenu(Menu mainMenu) void InitMainMenu(Menu mainMenu)
{ {
var mainMenuCommands = App.ExportProvider.GetExports<ICommand, IMainMenuCommandMetadata>("MainMenuCommand"); var mainMenuCommands = exportProvider.GetExports<ICommand, IMainMenuCommandMetadata>("MainMenuCommand");
// Start by constructing the individual flat menus // Start by constructing the individual flat menus
var parentMenuItems = new Dictionary<string, MenuItem>(); var parentMenuItems = new Dictionary<string, MenuItem>();
var menuGroups = mainMenuCommands.OrderBy(c => c.Metadata?.MenuOrder).GroupBy(c => c.Metadata?.ParentMenuID).ToArray(); var menuGroups = mainMenuCommands.OrderBy(c => c.Metadata?.MenuOrder).GroupBy(c => c.Metadata?.ParentMenuID).ToArray();
@ -150,11 +151,11 @@ namespace ICSharpCode.ILSpy.Util
windowMenuItem.ItemsSource = allItems; windowMenuItem.ItemsSource = allItems;
} }
static void InitToolbar(ToolBar toolBar) void InitToolbar(ToolBar toolBar)
{ {
int navigationPos = 0; int navigationPos = 0;
int openPos = 1; int openPos = 1;
var toolbarCommandsByTitle = App.ExportProvider.GetExports<ICommand, IToolbarCommandMetadata>("ToolbarCommand") var toolbarCommandsByTitle = exportProvider.GetExports<ICommand, IToolbarCommandMetadata>("ToolbarCommand")
.OrderBy(c => c.Metadata?.ToolbarOrder) .OrderBy(c => c.Metadata?.ToolbarOrder)
.GroupBy(c => c.Metadata?.ToolbarCategory); .GroupBy(c => c.Metadata?.ToolbarCategory);

9
ILSpy/Util/SettingsService.cs

@ -19,6 +19,7 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.ComponentModel; using System.ComponentModel;
using System.Composition;
using System.Xml.Linq; using System.Xml.Linq;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
@ -110,13 +111,9 @@ namespace ICSharpCode.ILSpy.Util
} }
} }
public class SettingsService : SettingsServiceBase public class SettingsService() : SettingsServiceBase(LoadSettings())
{ {
public static readonly SettingsService Instance = new(); public static readonly SettingsService Instance = App.ExportProvider.GetExportedValue<SettingsService>();
private SettingsService() : base(LoadSettings())
{
}
public SessionSettings SessionSettings => GetSettings<SessionSettings>(); public SessionSettings SessionSettings => GetSettings<SessionSettings>();

18
ILSpy/ViewModels/ManageAssemblyListsViewModel.cs

@ -35,11 +35,13 @@ namespace ICSharpCode.ILSpy.ViewModels
{ {
private readonly AssemblyListManager manager; private readonly AssemblyListManager manager;
private readonly Window parent; private readonly Window parent;
private readonly SessionSettings sessionSettings;
public ManageAssemblyListsViewModel(Window parent) public ManageAssemblyListsViewModel(Window parent, SettingsService settingsService)
{ {
this.manager = SettingsService.Instance.AssemblyListManager; this.manager = settingsService.AssemblyListManager;
this.parent = parent; this.parent = parent;
this.sessionSettings = settingsService.SessionSettings;
NewCommand = new DelegateCommand(ExecuteNew); NewCommand = new DelegateCommand(ExecuteNew);
CloneCommand = new DelegateCommand(ExecuteClone, CanExecuteClone); CloneCommand = new DelegateCommand(ExecuteClone, CanExecuteClone);
@ -174,7 +176,7 @@ namespace ICSharpCode.ILSpy.ViewModels
return; return;
manager.ClearAll(); manager.ClearAll();
manager.CreateDefaultAssemblyLists(); manager.CreateDefaultAssemblyLists();
SettingsService.Instance.SessionSettings.ActiveAssemblyList = manager.AssemblyLists[0]; sessionSettings.ActiveAssemblyList = manager.AssemblyLists[0];
} }
private void ExecuteDelete() private void ExecuteDelete()
@ -189,9 +191,9 @@ namespace ICSharpCode.ILSpy.ViewModels
if (manager.AssemblyLists.Count > 0) if (manager.AssemblyLists.Count > 0)
{ {
SelectedAssemblyList = manager.AssemblyLists[Math.Max(0, index - 1)]; SelectedAssemblyList = manager.AssemblyLists[Math.Max(0, index - 1)];
if (SettingsService.Instance.SessionSettings.ActiveAssemblyList == assemblyList) if (sessionSettings.ActiveAssemblyList == assemblyList)
{ {
SettingsService.Instance.SessionSettings.ActiveAssemblyList = SelectedAssemblyList; sessionSettings.ActiveAssemblyList = SelectedAssemblyList;
} }
} }
} }
@ -232,9 +234,9 @@ namespace ICSharpCode.ILSpy.ViewModels
string assemblyList = SelectedAssemblyList; string assemblyList = SelectedAssemblyList;
SelectedAssemblyList = dlg.ListName; SelectedAssemblyList = dlg.ListName;
manager.RenameList(assemblyList, dlg.ListName); manager.RenameList(assemblyList, dlg.ListName);
if (SettingsService.Instance.SessionSettings.ActiveAssemblyList == assemblyList) if (sessionSettings.ActiveAssemblyList == assemblyList)
{ {
SettingsService.Instance.SessionSettings.ActiveAssemblyList = manager.AssemblyLists[manager.AssemblyLists.Count - 1]; sessionSettings.ActiveAssemblyList = manager.AssemblyLists[manager.AssemblyLists.Count - 1];
} }
} }
} }
@ -272,7 +274,7 @@ namespace ICSharpCode.ILSpy.ViewModels
private void ExecuteSelectAssemblyList() private void ExecuteSelectAssemblyList()
{ {
SettingsService.Instance.SessionSettings.ActiveAssemblyList = SelectedAssemblyList; sessionSettings.ActiveAssemblyList = SelectedAssemblyList;
this.parent.Close(); this.parent.Close();
} }
} }

23
ILSpy/ViewModels/TabPageModel.cs

@ -21,6 +21,8 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using TomsToolbox.Wpf; using TomsToolbox.Wpf;
@ -29,8 +31,16 @@ namespace ICSharpCode.ILSpy.ViewModels
{ {
public class TabPageModel : PaneModel public class TabPageModel : PaneModel
{ {
public TabPageModel() public AssemblyTreeModel AssemblyTreeModel { get; }
public SettingsService SettingsService { get; }
public LanguageService LanguageService { get; }
public TabPageModel(AssemblyTreeModel assemblyTreeModel, SettingsService settingsService, LanguageService languageService)
{ {
AssemblyTreeModel = assemblyTreeModel;
SettingsService = settingsService;
LanguageService = languageService;
this.Title = Properties.Resources.NewTab; this.Title = Properties.Resources.NewTab;
} }
@ -72,7 +82,7 @@ namespace ICSharpCode.ILSpy.ViewModels
{ {
if (!(tabPage.Content is DecompilerTextView textView)) if (!(tabPage.Content is DecompilerTextView textView))
{ {
textView = new DecompilerTextView(); textView = new DecompilerTextView(tabPage);
tabPage.Content = textView; tabPage.Content = textView;
} }
tabPage.Title = Properties.Resources.Decompiling; tabPage.Title = Properties.Resources.Decompiling;
@ -83,7 +93,7 @@ namespace ICSharpCode.ILSpy.ViewModels
{ {
if (!(tabPage.Content is DecompilerTextView textView)) if (!(tabPage.Content is DecompilerTextView textView))
{ {
textView = new DecompilerTextView(); textView = new DecompilerTextView(tabPage);
tabPage.Content = textView; tabPage.Content = textView;
} }
string oldTitle = tabPage.Title; string oldTitle = tabPage.Title;
@ -105,7 +115,7 @@ namespace ICSharpCode.ILSpy.ViewModels
{ {
if (!(tabPage.Content is DecompilerTextView textView)) if (!(tabPage.Content is DecompilerTextView textView))
{ {
textView = new DecompilerTextView(); textView = new DecompilerTextView(tabPage);
tabPage.Content = textView; tabPage.Content = textView;
} }
string oldTitle = tabPage.Title; string oldTitle = tabPage.Title;
@ -129,6 +139,11 @@ namespace ICSharpCode.ILSpy.ViewModels
focusable?.Focus(); focusable?.Focus();
} }
public static DecompilationOptions CreateDecompilationOptions(this TabPageModel tabPage)
{
return new(tabPage.LanguageService.LanguageVersion, tabPage.SettingsService.DecompilerSettings, tabPage.SettingsService.DisplaySettings) { Progress = tabPage.Content as IProgress<DecompilationProgress> };
}
} }
public interface IHaveState public interface IHaveState

20
ILSpy/Views/DebugSteps.xaml.cs

@ -7,6 +7,7 @@ using System.Windows.Input;
using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.IL.Transforms; using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpy.ViewModels;
@ -18,6 +19,10 @@ namespace ICSharpCode.ILSpy
[NonShared] [NonShared]
public partial class DebugSteps : UserControl public partial class DebugSteps : UserControl
{ {
private readonly AssemblyTreeModel assemblyTreeModel;
private readonly SettingsService settingsService;
private readonly LanguageService languageService;
static readonly ILAstWritingOptions writingOptions = new ILAstWritingOptions { static readonly ILAstWritingOptions writingOptions = new ILAstWritingOptions {
UseFieldSugar = true, UseFieldSugar = true,
UseLogicOperationSugar = true UseLogicOperationSugar = true
@ -28,8 +33,12 @@ namespace ICSharpCode.ILSpy
#if DEBUG #if DEBUG
ILAstLanguage language; ILAstLanguage language;
#endif #endif
public DebugSteps() public DebugSteps(AssemblyTreeModel assemblyTreeModel, SettingsService settingsService, LanguageService languageService)
{ {
this.assemblyTreeModel = assemblyTreeModel;
this.settingsService = settingsService;
this.languageService = languageService;
InitializeComponent(); InitializeComponent();
#if DEBUG #if DEBUG
@ -38,7 +47,7 @@ namespace ICSharpCode.ILSpy
writingOptions.PropertyChanged += WritingOptions_PropertyChanged; writingOptions.PropertyChanged += WritingOptions_PropertyChanged;
if (LanguageService.Instance.Language is ILAstLanguage l) if (languageService.Language is ILAstLanguage l)
{ {
l.StepperUpdated += ILAstStepperUpdated; l.StepperUpdated += ILAstStepperUpdated;
language = l; language = l;
@ -72,7 +81,7 @@ namespace ICSharpCode.ILSpy
{ {
language.StepperUpdated -= ILAstStepperUpdated; language.StepperUpdated -= ILAstStepperUpdated;
} }
if (LanguageService.Instance.Language is ILAstLanguage l) if (languageService.Language is ILAstLanguage l)
{ {
l.StepperUpdated += ILAstStepperUpdated; l.StepperUpdated += ILAstStepperUpdated;
language = l; language = l;
@ -123,10 +132,9 @@ namespace ICSharpCode.ILSpy
void DecompileAsync(int step, bool isDebug = false) void DecompileAsync(int step, bool isDebug = false)
{ {
lastSelectedStep = step; lastSelectedStep = step;
var window = MainWindow.Instance;
var state = DockWorkspace.Instance.ActiveTabPage.GetState(); var state = DockWorkspace.Instance.ActiveTabPage.GetState();
DockWorkspace.Instance.ActiveTabPage.ShowTextViewAsync(textView => textView.DecompileAsync(window.AssemblyTreeModel.CurrentLanguage, window.AssemblyTreeModel.SelectedNodes, DockWorkspace.Instance.ActiveTabPage.ShowTextViewAsync(textView => textView.DecompileAsync(assemblyTreeModel.CurrentLanguage, assemblyTreeModel.SelectedNodes,
new DecompilationOptions(window.AssemblyTreeModel.CurrentLanguageVersion, SettingsService.Instance.DecompilerSettings, SettingsService.Instance.DisplaySettings) { new DecompilationOptions(assemblyTreeModel.CurrentLanguageVersion, settingsService.DecompilerSettings, settingsService.DisplaySettings) {
StepLimit = step, StepLimit = step,
IsDebug = isDebug, IsDebug = isDebug,
TextViewState = state as TextView.DecompilerTextViewState TextViewState = state as TextView.DecompilerTextViewState

4
ILSpy/Views/ManageAssemblyLIstsDialog.xaml.cs

@ -29,10 +29,10 @@ namespace ICSharpCode.ILSpy
/// </summary> /// </summary>
public partial class ManageAssemblyListsDialog : Window public partial class ManageAssemblyListsDialog : Window
{ {
public ManageAssemblyListsDialog() public ManageAssemblyListsDialog(SettingsService settingsService)
{ {
InitializeComponent(); InitializeComponent();
DataContext = new ManageAssemblyListsViewModel(this); DataContext = new ManageAssemblyListsViewModel(this, settingsService);
} }
private void PreconfiguredAssemblyListsMenuClick(object sender, RoutedEventArgs e) private void PreconfiguredAssemblyListsMenuClick(object sender, RoutedEventArgs e)

5
TestPlugin/MainMenuCommand.cs

@ -4,6 +4,7 @@
using System.Composition; using System.Composition;
using ICSharpCode.ILSpy; using ICSharpCode.ILSpy;
using ICSharpCode.ILSpy.AssemblyTree;
namespace TestPlugin namespace TestPlugin
{ {
@ -19,11 +20,11 @@ namespace TestPlugin
// ToolbarOrder: controls the order in which the items appear (items are sorted by this value) // ToolbarOrder: controls the order in which the items appear (items are sorted by this value)
[ExportToolbarCommand(ToolTip = "Clears the current assembly list", ToolbarIcon = "Clear.png", ToolbarCategory = "Open", ToolbarOrder = 1.5)] [ExportToolbarCommand(ToolTip = "Clears the current assembly list", ToolbarIcon = "Clear.png", ToolbarCategory = "Open", ToolbarOrder = 1.5)]
[Shared] [Shared]
public class UnloadAllAssembliesCommand : SimpleCommand public class UnloadAllAssembliesCommand(AssemblyTreeModel assemblyTreeModel) : SimpleCommand
{ {
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
foreach (var loadedAssembly in MainWindow.Instance.AssemblyTreeModel.AssemblyList.GetAssemblies()) foreach (var loadedAssembly in assemblyTreeModel.AssemblyList.GetAssemblies())
{ {
loadedAssembly.AssemblyList.Unload(loadedAssembly); loadedAssembly.AssemblyList.Unload(loadedAssembly);
} }

Loading…
Cancel
Save