diff --git a/ILSpy.ReadyToRun/ReadyToRunDisassembler.cs b/ILSpy.ReadyToRun/ReadyToRunDisassembler.cs index ce9e62a1e..8d08b413e 100644 --- a/ILSpy.ReadyToRun/ReadyToRunDisassembler.cs +++ b/ILSpy.ReadyToRun/ReadyToRunDisassembler.cs @@ -38,12 +38,14 @@ namespace ICSharpCode.ILSpy.ReadyToRun private readonly ITextOutput output; private readonly ReadyToRunReader reader; 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.reader = reader; this.runtimeFunction = runtimeFunction; + this.settingsService = settingsService; } 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; WriteCommentLine(readyToRunMethod.SignatureString); - var options = SettingsService.Instance.GetSettings<ReadyToRunOptions>(); + var options = settingsService.GetSettings<ReadyToRunOptions>(); if (options.IsShowGCInfo) { diff --git a/ILSpy.ReadyToRun/ReadyToRunLanguage.cs b/ILSpy.ReadyToRun/ReadyToRunLanguage.cs index 78e478861..26a3dc0df 100644 --- a/ILSpy.ReadyToRun/ReadyToRunLanguage.cs +++ b/ILSpy.ReadyToRun/ReadyToRunLanguage.cs @@ -38,6 +38,10 @@ using ICSharpCode.ILSpyX; using ILCompiler.Reflection.ReadyToRun; +using TomsToolbox.Composition; + +using MetadataReader = System.Reflection.Metadata.MetadataReader; + namespace ICSharpCode.ILSpy.ReadyToRun { #if STRESS @@ -97,7 +101,7 @@ namespace ICSharpCode.ILSpy.ReadyToRun [Export(typeof(Language))] [Shared] - internal class ReadyToRunLanguage : Language + internal class ReadyToRunLanguage(SettingsService settingsService, IExportProvider exportProvider) : Language { private static readonly ConditionalWeakTable<MetadataFile, ReadyToRunReaderCacheEntry> readyToRunReaders = new ConditionalWeakTable<MetadataFile, ReadyToRunReaderCacheEntry>(); @@ -175,7 +179,7 @@ namespace ICSharpCode.ILSpy.ReadyToRun .GroupBy(m => m.MethodHandle) .ToDictionary(g => g.Key, g => g.ToArray()); } - var displaySettings = SettingsService.Instance.DisplaySettings; + var displaySettings = settingsService.DisplaySettings; bool showMetadataTokens = displaySettings.ShowMetadataTokens; bool showMetadataTokensInBase10 = displaySettings.ShowMetadataTokensInBase10; #if STRESS @@ -205,7 +209,7 @@ namespace ICSharpCode.ILSpy.ReadyToRun 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) { - return LanguageService.Instance.ILLanguage.GetRichTextTooltip(entity); + return exportProvider.GetExportedValue<LanguageService>().ILLanguage.GetRichTextTooltip(entity); } private ReadyToRunReaderCacheEntry GetReader(LoadedAssembly assembly, MetadataFile file) diff --git a/ILSpy.Tests/Analyzers/MemberImplementsInterfaceAnalyzerTests.cs b/ILSpy.Tests/Analyzers/MemberImplementsInterfaceAnalyzerTests.cs index 7b6f77c28..1149418e8 100644 --- a/ILSpy.Tests/Analyzers/MemberImplementsInterfaceAnalyzerTests.cs +++ b/ILSpy.Tests/Analyzers/MemberImplementsInterfaceAnalyzerTests.cs @@ -145,7 +145,7 @@ namespace ICSharpCode.ILSpy.Tests.Analyzers var analyzer = new MemberImplementsInterfaceAnalyzer(); // 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.That(results, Is.Not.Null); diff --git a/ILSpy.Tests/Analyzers/MethodUsesAnalyzerTests.cs b/ILSpy.Tests/Analyzers/MethodUsesAnalyzerTests.cs index 79bbbee7d..033deaa1d 100644 --- a/ILSpy.Tests/Analyzers/MethodUsesAnalyzerTests.cs +++ b/ILSpy.Tests/Analyzers/MethodUsesAnalyzerTests.cs @@ -30,7 +30,7 @@ namespace ICSharpCode.ILSpy.Tests.Analyzers testAssembly = assemblyList.OpenAssembly(typeof(MethodUsesAnalyzerTests).Assembly.Location); assemblyList.OpenAssembly(typeof(void).Assembly.Location); testAssemblyTypeSystem = testAssembly.GetTypeSystemOrNull(); - language = new CSharpLanguage([]); + language = new CSharpLanguage(); typeDefinition = testAssemblyTypeSystem.FindType(typeof(TestCases.Main.MainAssembly)).GetDefinition(); } diff --git a/ILSpy.Tests/Analyzers/TypeUsedByAnalyzerTests.cs b/ILSpy.Tests/Analyzers/TypeUsedByAnalyzerTests.cs index 2a47b84ac..972cb6fc7 100644 --- a/ILSpy.Tests/Analyzers/TypeUsedByAnalyzerTests.cs +++ b/ILSpy.Tests/Analyzers/TypeUsedByAnalyzerTests.cs @@ -41,7 +41,7 @@ namespace ICSharpCode.ILSpy.Tests.Analyzers assemblyList = new AssemblyList(); testAssembly = assemblyList.OpenAssembly(typeof(MethodUsesAnalyzerTests).Assembly.Location); testAssemblyTypeSystem = new DecompilerTypeSystem(testAssembly.GetMetadataFileOrNull(), testAssembly.GetAssemblyResolver()); - language = new CSharpLanguage([]); + language = new CSharpLanguage(); } [Test] diff --git a/ILSpy/AboutPage.cs b/ILSpy/AboutPage.cs index 5683b253d..525d9b892 100644 --- a/ILSpy/AboutPage.cs +++ b/ILSpy/AboutPage.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections.Generic; using System.Composition; using System.IO; using System.Text.RegularExpressions; @@ -28,6 +29,7 @@ using System.Windows.Navigation; using ICSharpCode.AvalonEdit.Rendering; using ICSharpCode.Decompiler; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.Themes; @@ -38,17 +40,22 @@ namespace ICSharpCode.ILSpy { [ExportMainMenuCommand(ParentMenuID = nameof(Resources._Help), Header = nameof(Resources._About), MenuOrder = 99999)] [Shared] - sealed class AboutPage : SimpleCommand + public sealed class AboutPageCommand(AssemblyTreeModel assemblyTreeModel) : SimpleCommand { public override void Execute(object parameter) { - MainWindow.Instance.AssemblyTreeModel.NavigateTo( + assemblyTreeModel.NavigateTo( new RequestNavigateEventArgs(new Uri("resource://aboutpage"), null), 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() { Title = Resources.About, @@ -86,7 +93,7 @@ namespace ICSharpCode.ILSpy }); output.WriteLine(); - foreach (var plugin in App.ExportProvider.GetExportedValues<IAboutPageAddition>()) + foreach (var plugin in aboutPageAdditions) plugin.Write(output); output.WriteLine(); output.Address = new Uri("resource://AboutPage"); diff --git a/ILSpy/Analyzers/AnalyzeCommand.cs b/ILSpy/Analyzers/AnalyzeCommand.cs index e29dacb23..30c5a9ee7 100644 --- a/ILSpy/Analyzers/AnalyzeCommand.cs +++ b/ILSpy/Analyzers/AnalyzeCommand.cs @@ -20,17 +20,18 @@ using System.Composition; using System.Linq; using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TreeNodes; +using TomsToolbox.Composition; + namespace ICSharpCode.ILSpy.Analyzers { [ExportContextMenuEntry(Header = nameof(Resources.Analyze), Icon = "Images/Search", Category = nameof(Resources.Analyze), InputGestureText = "Ctrl+R", Order = 100)] [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) { 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()) { - AnalyzerTreeView.Analyze(node.Member); + analyzerTreeView.Analyze(node.Member); } } 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) { - return MainWindow.Instance.AssemblyTreeModel.SelectedNodes.All(n => n is IMemberTreeNode); + return assemblyTreeModel.SelectedNodes.All(n => n is IMemberTreeNode); } 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); } } } diff --git a/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs b/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs index 7c3d484bc..8609fc674 100644 --- a/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs +++ b/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs @@ -61,7 +61,7 @@ namespace ICSharpCode.ILSpy.Analyzers var context = new AnalyzerContext() { CancellationToken = ct, Language = Language, - AssemblyList = MainWindow.Instance.AssemblyTreeModel.AssemblyList + AssemblyList = AssemblyTreeModel.AssemblyList }; var results = analyzer.Analyze(symbol, context).Select(SymbolTreeNodeFactory); if (context.SortResults) diff --git a/ILSpy/Analyzers/AnalyzerTreeNode.cs b/ILSpy/Analyzers/AnalyzerTreeNode.cs index d2cffeb49..2775634a6 100644 --- a/ILSpy/Analyzers/AnalyzerTreeNode.cs +++ b/ILSpy/Analyzers/AnalyzerTreeNode.cs @@ -17,15 +17,20 @@ // DEALINGS IN THE SOFTWARE. using System.Collections.Generic; +using System.Linq; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpyX; +using ICSharpCode.ILSpyX.Analyzers; using ICSharpCode.ILSpyX.TreeView; +using TomsToolbox.Composition; + namespace ICSharpCode.ILSpy.Analyzers { public abstract class AnalyzerTreeNode : SharpTreeNode { - public Language Language => LanguageService.Instance.Language; + public static Language Language => App.ExportProvider.GetExportedValue<LanguageService>().Language; public override bool CanDelete() { @@ -42,6 +47,13 @@ namespace ICSharpCode.ILSpy.Analyzers 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> /// Handles changes to the assembly list. /// </summary> diff --git a/ILSpy/Analyzers/AnalyzerTreeViewModel.cs b/ILSpy/Analyzers/AnalyzerTreeViewModel.cs index ce45558b9..c325d0151 100644 --- a/ILSpy/Analyzers/AnalyzerTreeViewModel.cs +++ b/ILSpy/Analyzers/AnalyzerTreeViewModel.cs @@ -24,6 +24,7 @@ using System.Windows.Input; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.Analyzers.TreeNodes; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.ViewModels; @@ -38,12 +39,12 @@ namespace ICSharpCode.ILSpy.Analyzers { public const string PaneContentId = "analyzerPane"; - public AnalyzerTreeViewModel() + public AnalyzerTreeViewModel(AssemblyTreeModel assemblyTreeModel) { ContentId = PaneContentId; Title = Properties.Resources.Analyze; ShortcutKey = new(Key.R, ModifierKeys.Control); - AssociatedCommand = ILSpyCommands.Analyze; + AssociatedCommand = new AnalyzeCommand(assemblyTreeModel, this); } public AnalyzerRootNode Root { get; } = new(); diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs index 8b6ff6f03..f8fccd112 100644 --- a/ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs +++ b/ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs @@ -17,15 +17,12 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Linq; +using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.TreeNodes; namespace ICSharpCode.ILSpy.Analyzers.TreeNodes { - using ICSharpCode.Decompiler.TypeSystem; - using ICSharpCode.ILSpyX.Analyzers; - internal sealed class AnalyzedEventTreeNode : AnalyzerEntityTreeNode { readonly IEvent analyzedEvent; @@ -54,16 +51,12 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes if (TryFindBackingField(analyzedEvent, out var backingField)) this.Children.Add(new AnalyzedFieldTreeNode(backingField)); - //foreach (var accessor in analyzedEvent.OtherMethods) - // 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)) + foreach (var lazy in Analyzers) { var analyzer = lazy.Value; 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; 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; return true; diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs index 1f2b9b9a3..7317841d1 100644 --- a/ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs +++ b/ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs @@ -17,11 +17,9 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Linq; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.TreeNodes; -using ICSharpCode.ILSpyX.Analyzers; namespace ICSharpCode.ILSpy.Analyzers.TreeNodes { @@ -41,13 +39,12 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes protected override void LoadChildren() { - var analyzers = App.ExportProvider.GetExports<IAnalyzer, IAnalyzerMetadata>("Analyzer"); - foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order)) + foreach (var lazy in Analyzers) { var analyzer = lazy.Value; if (analyzer.Show(analyzedField)) { - this.Children.Add(new AnalyzerSearchTreeNode(analyzedField, analyzer, lazy.Metadata.Header)); + this.Children.Add(new AnalyzerSearchTreeNode(analyzedField, analyzer, lazy.Metadata?.Header)); } } } diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs index b7cee8ede..283b30a3f 100644 --- a/ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs +++ b/ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs @@ -17,11 +17,9 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Linq; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.TreeNodes; -using ICSharpCode.ILSpyX.Analyzers; namespace ICSharpCode.ILSpy.Analyzers.TreeNodes { @@ -43,8 +41,7 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes protected override void LoadChildren() { - var analyzers = App.ExportProvider.GetExports<IAnalyzer, IAnalyzerMetadata>("Analyzer"); - foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order)) + foreach (var lazy in Analyzers) { var analyzer = lazy.Value; if (analyzer.Show(analyzedMethod)) diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedModuleTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedModuleTreeNode.cs index 7f343fb78..a85096147 100644 --- a/ILSpy/Analyzers/TreeNodes/AnalyzedModuleTreeNode.cs +++ b/ILSpy/Analyzers/TreeNodes/AnalyzedModuleTreeNode.cs @@ -17,11 +17,9 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Linq; using System.Windows; using ICSharpCode.Decompiler.TypeSystem; -using ICSharpCode.ILSpyX.Analyzers; using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions; namespace ICSharpCode.ILSpy.Analyzers.TreeNodes @@ -42,8 +40,7 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes protected override void LoadChildren() { - var analyzers = App.ExportProvider.GetExports<IAnalyzer, IAnalyzerMetadata>("Analyzer"); - foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order)) + foreach (var lazy in Analyzers) { var analyzer = lazy.Value; if (analyzer.Show(analyzedModule)) diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs index d19bc3e73..7a4d2fdfa 100644 --- a/ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs +++ b/ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs @@ -17,11 +17,9 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Linq; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.TreeNodes; -using ICSharpCode.ILSpyX.Analyzers; namespace ICSharpCode.ILSpy.Analyzers.TreeNodes { @@ -48,11 +46,8 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes this.Children.Add(new AnalyzedAccessorTreeNode(analyzedProperty.Getter, "get")); if (analyzedProperty.CanSet) 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.OrderBy(item => item.Metadata.Order)) + foreach (var lazy in Analyzers) { var analyzer = lazy.Value; if (analyzer.Show(analyzedProperty)) diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs index 6836944eb..cb3ccc609 100644 --- a/ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs +++ b/ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs @@ -17,11 +17,9 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Linq; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.TreeNodes; -using ICSharpCode.ILSpyX.Analyzers; namespace ICSharpCode.ILSpy.Analyzers.TreeNodes { @@ -41,8 +39,7 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes protected override void LoadChildren() { - var analyzers = App.ExportProvider.GetExports<IAnalyzer, IAnalyzerMetadata>("Analyzer"); - foreach (var lazy in analyzers.OrderBy(item => item.Metadata.Order)) + foreach (var lazy in Analyzers) { var analyzer = lazy.Value; if (analyzer.Show(analyzedType)) diff --git a/ILSpy/App.xaml.cs b/ILSpy/App.xaml.cs index 0ae19f9e1..05c077751 100644 --- a/ILSpy/App.xaml.cs +++ b/ILSpy/App.xaml.cs @@ -71,8 +71,10 @@ namespace ICSharpCode.ILSpy var cmdArgs = Environment.GetCommandLineArgs().Skip(1); CommandLineArguments = CommandLineArguments.Create(cmdArgs); + var settingsService = new SettingsService(); + bool forceSingleInstance = (CommandLineArguments.SingleInstance ?? true) - && !SettingsService.Instance.MiscSettings.AllowMultipleInstances; + && !settingsService.MiscSettings.AllowMultipleInstances; if (forceSingleInstance) { SingleInstance.Attach(); // will auto-exit for second instance @@ -81,7 +83,7 @@ namespace ICSharpCode.ILSpy 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. Exit += (_, _) => MessageBox.Show(StartupExceptions.FormatExceptions(), "Sorry we crashed!"); @@ -106,7 +108,7 @@ namespace ICSharpCode.ILSpy // Add data templates registered via MEF. Resources.MergedDictionaries.Add(DataTemplateManager.CreateDynamicDataTemplates(ExportProvider)); - var sessionSettings = SettingsService.Instance.SessionSettings; + var sessionSettings = settingsService.SessionSettings; ThemeManager.Current.Theme = sessionSettings.Theme; if (!string.IsNullOrEmpty(sessionSettings.CurrentCulture)) { @@ -129,7 +131,7 @@ namespace ICSharpCode.ILSpy MessageBox.Show(unknownArguments, "ILSpy Unknown Command Line Arguments Passed"); } - SettingsService.Instance.AssemblyListManager.CreateDefaultAssemblyLists(); + settingsService.AssemblyListManager.CreateDefaultAssemblyLists(); } public new static App Current => (App)Application.Current; @@ -187,6 +189,10 @@ namespace ICSharpCode.ILSpy services.BindExports(Assembly.GetExecutingAssembly()); // Add the settings service 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 }); @@ -209,7 +215,7 @@ namespace ICSharpCode.ILSpy { base.OnStartup(e); - MainWindow = new(); + MainWindow = ExportProvider.GetExportedValue<MainWindow>(); MainWindow.Show(); } diff --git a/ILSpy/AssemblyTree/AssemblyTreeModel.cs b/ILSpy/AssemblyTree/AssemblyTreeModel.cs index 954310192..59d3ba47e 100644 --- a/ILSpy/AssemblyTree/AssemblyTreeModel.cs +++ b/ILSpy/AssemblyTree/AssemblyTreeModel.cs @@ -47,6 +47,7 @@ using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX.Settings; using ICSharpCode.ILSpyX.TreeView; +using TomsToolbox.Composition; using TomsToolbox.Essentials; using TomsToolbox.Wpf; @@ -67,9 +68,20 @@ namespace ICSharpCode.ILSpy.AssemblyTree private readonly NavigationHistory<NavigationState> history = new(); 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; ContentId = PaneContentId; IsCloseable = false; @@ -80,7 +92,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree refreshThrottle = new DispatcherThrottle(DispatcherPriority.Background, RefreshInternal); - AssemblyList = SettingsService.Instance.CreateEmptyAssemblyList(); + AssemblyList = settingsService.CreateEmptyAssemblyList(); } private void Settings_PropertyChanged(object? sender, PropertyChangedEventArgs e) @@ -151,7 +163,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree { LoadAssemblies(args.AssembliesToLoad, commandLineLoadedAssemblies, focusNode: false); if (args.Language != null) - LanguageService.Instance.Language = LanguageService.Instance.GetLanguage(args.Language); + languageService.Language = languageService.GetLanguage(args.Language); return true; } @@ -161,7 +173,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree /// </summary> private async Task HandleCommandLineArgumentsAfterShowList(CommandLineArguments args, ISettingsProvider? spySettings = null) { - var sessionSettings = SettingsService.Instance.SessionSettings; + var sessionSettings = settingsService.SessionSettings; var relevantAssemblies = commandLineLoadedAssemblies.ToList(); commandLineLoadedAssemblies.Clear(); // clear references once we don't need them anymore @@ -170,10 +182,8 @@ namespace ICSharpCode.ILSpy.AssemblyTree if (args.Search != null) { - var searchPane = App.ExportProvider.GetExportedValue<SearchPaneModel>(); - - searchPane.SearchTerm = args.Search; - searchPane.Show(); + this.searchPaneModel.SearchTerm = args.Search; + this.searchPaneModel.Show(); } } @@ -290,11 +300,11 @@ namespace ICSharpCode.ILSpy.AssemblyTree SelectNode(node); // only if not showing the about page, perform the update check: - await MainWindow.Instance.ShowMessageIfUpdatesAvailableAsync(spySettings); + await App.Current.MainWindow.ShowMessageIfUpdatesAvailableAsync(spySettings); } else { - DockWorkspace.Instance.ActiveTabPage.ShowTextView(AboutPage.Display); + DockWorkspace.Instance.ActiveTabPage.ShowTextView(aboutPage.Display); } } } @@ -363,11 +373,11 @@ namespace ICSharpCode.ILSpy.AssemblyTree public void Initialize() { - AssemblyList = SettingsService.Instance.LoadInitialAssemblyList(); + AssemblyList = settingsService.LoadInitialAssemblyList(); HandleCommandLineArguments(App.CommandLineArguments); - var loadPreviousAssemblies = SettingsService.Instance.MiscSettings.LoadPreviousAssemblies; + var loadPreviousAssemblies = settingsService.MiscSettings.LoadPreviousAssemblies; if (AssemblyList.GetAssemblies().Length == 0 && AssemblyList.ListName == AssemblyListManager.DefaultListName && loadPreviousAssemblies) @@ -377,7 +387,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree ShowAssemblyList(AssemblyList); - var sessionSettings = SettingsService.Instance.SessionSettings; + var sessionSettings = settingsService.SessionSettings; if (sessionSettings.ActiveAutoLoadedAssembly != null && File.Exists(sessionSettings.ActiveAutoLoadedAssembly)) { @@ -389,7 +399,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree 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)) { @@ -416,7 +426,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree 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 if (list.ListName != AssemblyList.ListName) { @@ -655,8 +665,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree } if (protocol != "decompile") { - var protocolHandlers = App.ExportProvider.GetExportedValues<IProtocolHandler>(); - foreach (var handler in protocolHandlers) + foreach (var handler in exportProvider.GetExportedValues<IProtocolHandler>()) { var node = handler.Resolve(protocol, file, unresolvedEntity.Handle, out bool newTabPage); if (node != null) @@ -793,7 +802,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree return; } - var options = LanguageService.Instance.CreateDecompilationOptions(activeTabPage); + var options = activeTabPage.CreateDecompilationOptions(); options.TextViewState = newState; 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); } - 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 { get { @@ -858,7 +867,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree if (e.Uri.Host == "aboutpage") { RecordHistory(); - DockWorkspace.Instance.ActiveTabPage.ShowTextView(AboutPage.Display); + DockWorkspace.Instance.ActiveTabPage.ShowTextView(aboutPage.Display); e.Handled = true; return; } @@ -912,7 +921,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree { var path = GetPathForNode(SelectedItem); - ShowAssemblyList(SettingsService.Instance.AssemblyListManager.LoadList(AssemblyList.ListName)); + ShowAssemblyList(settingsService.AssemblyListManager.LoadList(AssemblyList.ListName)); SelectNode(FindNodeByPath(path, true), inNewTabPage: false); RefreshDecompiledView(); diff --git a/ILSpy/Commands/CheckForUpdatesCommand.cs b/ILSpy/Commands/CheckForUpdatesCommand.cs index 75ab702e7..5ac9b1fc6 100644 --- a/ILSpy/Commands/CheckForUpdatesCommand.cs +++ b/ILSpy/Commands/CheckForUpdatesCommand.cs @@ -25,16 +25,11 @@ namespace ICSharpCode.ILSpy { [ExportMainMenuCommand(ParentMenuID = nameof(Resources._Help), Header = nameof(Resources._CheckUpdates), MenuOrder = 5000)] [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) { - await MainWindow.Instance.ShowMessageIfUpdatesAvailableAsync(SettingsService.Instance.SpySettings, forceCheck: true); + await App.Current.MainWindow.ShowMessageIfUpdatesAvailableAsync(settingsService.SpySettings, forceCheck: true); } } } diff --git a/ILSpy/Commands/DecompileAllCommand.cs b/ILSpy/Commands/DecompileAllCommand.cs index 72aae604c..06c093a44 100644 --- a/ILSpy/Commands/DecompileAllCommand.cs +++ b/ILSpy/Commands/DecompileAllCommand.cs @@ -27,24 +27,19 @@ using System.Linq; using System.Threading.Tasks; using ICSharpCode.Decompiler; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TextView; +using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpyX; namespace ICSharpCode.ILSpy { [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDecompile), MenuCategory = nameof(Resources.Open), MenuOrder = 2.5)] [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) { return System.IO.Directory.Exists("c:\\temp\\decompiled"); @@ -55,7 +50,7 @@ namespace ICSharpCode.ILSpy Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => { AvalonEditTextOutput output = new AvalonEditTextOutput(); 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 }, delegate (LoadedAssembly asm) { if (!asm.HasLoadError) @@ -66,10 +61,10 @@ namespace ICSharpCode.ILSpy { try { - var options = LanguageService.Instance.CreateDecompilationOptions(DockWorkspace.Instance.ActiveTabPage); + var options = DockWorkspace.Instance.ActiveTabPage.CreateDecompilationOptions(); options.CancellationToken = ct; options.FullDecompilation = true; - new CSharpLanguage(resourceFileHandlers).DecompileAssembly(asm, new PlainTextOutput(writer), options); + new CSharpLanguage().DecompileAssembly(asm, new PlainTextOutput(writer), options); } 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)] [Shared] - sealed class Decompile100TimesCommand : SimpleCommand + sealed class Decompile100TimesCommand(AssemblyTreeModel assemblyTreeModel, LanguageService languageService) : SimpleCommand { public override void Execute(object parameter) { const int numRuns = 100; - var language = LanguageService.Instance.Language; - var nodes = MainWindow.Instance.AssemblyTreeModel.SelectedNodes.ToArray(); + var language = languageService.Language; + var nodes = assemblyTreeModel.SelectedNodes.ToArray(); DockWorkspace dockWorkspace = DockWorkspace.Instance; - var options = LanguageService.Instance.CreateDecompilationOptions(dockWorkspace.ActiveTabPage); + var options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions(); dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => { options.CancellationToken = ct; Stopwatch w = Stopwatch.StartNew(); diff --git a/ILSpy/Commands/DisassembleAllCommand.cs b/ILSpy/Commands/DisassembleAllCommand.cs index fea58925d..8b81e87b2 100644 --- a/ILSpy/Commands/DisassembleAllCommand.cs +++ b/ILSpy/Commands/DisassembleAllCommand.cs @@ -24,14 +24,16 @@ using System.Composition; using System.Diagnostics; using System.Threading.Tasks; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TextView; +using ICSharpCode.ILSpy.ViewModels; namespace ICSharpCode.ILSpy { [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDisassemble), MenuCategory = nameof(Resources.Open), MenuOrder = 2.5)] [Shared] - sealed class DisassembleAllCommand : SimpleCommand + sealed class DisassembleAllCommand(AssemblyTreeModel assemblyTreeModel, LanguageService languageService) : SimpleCommand { public override bool CanExecute(object parameter) { @@ -45,7 +47,7 @@ namespace ICSharpCode.ILSpy dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => { AvalonEditTextOutput output = new(); Parallel.ForEach( - Partitioner.Create(MainWindow.Instance.AssemblyTreeModel.AssemblyList.GetAssemblies(), loadBalance: true), + Partitioner.Create(assemblyTreeModel.AssemblyList.GetAssemblies(), loadBalance: true), new() { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct }, asm => { if (!asm.HasLoadError) @@ -56,7 +58,7 @@ namespace ICSharpCode.ILSpy { try { - var options = LanguageService.Instance.CreateDecompilationOptions(dockWorkspace.ActiveTabPage); + var options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions(); options.FullDecompilation = true; options.CancellationToken = ct; new ILLanguage().DecompileAssembly(asm, new Decompiler.PlainTextOutput(writer), options); diff --git a/ILSpy/Commands/ExitCommand.cs b/ILSpy/Commands/ExitCommand.cs index 1ba8a34e1..67f698bfe 100644 --- a/ILSpy/Commands/ExitCommand.cs +++ b/ILSpy/Commands/ExitCommand.cs @@ -27,7 +27,7 @@ namespace ICSharpCode.ILSpy { public override void Execute(object parameter) { - MainWindow.Instance.Close(); + App.Current.MainWindow.Close(); } } } \ No newline at end of file diff --git a/ILSpy/Commands/GeneratePdbContextMenuEntry.cs b/ILSpy/Commands/GeneratePdbContextMenuEntry.cs index d31a3160c..63f38d95f 100644 --- a/ILSpy/Commands/GeneratePdbContextMenuEntry.cs +++ b/ILSpy/Commands/GeneratePdbContextMenuEntry.cs @@ -29,10 +29,12 @@ using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.CSharp.ProjectDecompiler; using ICSharpCode.Decompiler.DebugInfo; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; +using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpyX; using Microsoft.Win32; @@ -41,14 +43,14 @@ namespace ICSharpCode.ILSpy { [ExportContextMenuEntry(Header = nameof(Resources.GeneratePortable))] [Shared] - class GeneratePdbContextMenuEntry : IContextMenuEntry + class GeneratePdbContextMenuEntry(LanguageService languageService) : IContextMenuEntry { public void Execute(TextViewContext context) { var assembly = (context.SelectedTreeNodes?.FirstOrDefault() as AssemblyTreeNode)?.LoadedAssembly; if (assembly == null) return; - GeneratePdbForAssembly(assembly); + GeneratePdbForAssembly(assembly, languageService); } public bool IsEnabled(TextViewContext context) => true; @@ -60,7 +62,7 @@ namespace ICSharpCode.ILSpy && tn.LoadedAssembly.IsLoadedAsValidAssembly; } - internal static void GeneratePdbForAssembly(LoadedAssembly assembly) + internal static void GeneratePdbForAssembly(LoadedAssembly assembly, LanguageService languageService) { var file = assembly.GetMetadataFileOrNull() as PEFile; if (!PortablePdbWriter.HasCodeViewDebugDirectoryEntry(file)) @@ -75,7 +77,7 @@ namespace ICSharpCode.ILSpy if (dlg.ShowDialog() != true) return; DockWorkspace dockWorkspace = DockWorkspace.Instance; - DecompilationOptions options = LanguageService.Instance.CreateDecompilationOptions(dockWorkspace.ActiveTabPage); + DecompilationOptions options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions(); string fileName = dlg.FileName; dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => { AvalonEditTextOutput output = new AvalonEditTextOutput(); @@ -108,21 +110,21 @@ namespace ICSharpCode.ILSpy [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.GeneratePortable), MenuCategory = nameof(Resources.Save))] [Shared] - class GeneratePdbMainMenuEntry : SimpleCommand + class GeneratePdbMainMenuEntry(AssemblyTreeModel assemblyTreeModel, LanguageService languageService) : SimpleCommand { public override bool CanExecute(object parameter) { - return MainWindow.Instance.AssemblyTreeModel.SelectedNodes?.Count() == 1 - && MainWindow.Instance.AssemblyTreeModel.SelectedNodes?.FirstOrDefault() is AssemblyTreeNode tn + return assemblyTreeModel.SelectedNodes?.Count() == 1 + && assemblyTreeModel.SelectedNodes?.FirstOrDefault() is AssemblyTreeNode tn && !tn.LoadedAssembly.HasLoadError; } 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) return; - GeneratePdbContextMenuEntry.GeneratePdbForAssembly(assembly); + GeneratePdbContextMenuEntry.GeneratePdbForAssembly(assembly, languageService); } } } diff --git a/ILSpy/Commands/ILSpyCommands.cs b/ILSpy/Commands/ILSpyCommands.cs deleted file mode 100644 index 50ace9379..000000000 --- a/ILSpy/Commands/ILSpyCommands.cs +++ /dev/null @@ -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(); - } -} diff --git a/ILSpy/Commands/ManageAssemblyListsCommand.cs b/ILSpy/Commands/ManageAssemblyListsCommand.cs index 63ab2f037..8172f2182 100644 --- a/ILSpy/Commands/ManageAssemblyListsCommand.cs +++ b/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)] [Shared] - sealed class ManageAssemblyListsCommand : SimpleCommand + sealed class ManageAssemblyListsCommand(SettingsService settingsService) : SimpleCommand { public override void Execute(object parameter) { - ManageAssemblyListsDialog dlg = new ManageAssemblyListsDialog(); - dlg.Owner = MainWindow.Instance; + ManageAssemblyListsDialog dlg = new ManageAssemblyListsDialog(settingsService); + dlg.Owner = App.Current.MainWindow; dlg.ShowDialog(); } } diff --git a/ILSpy/Commands/OpenFromGacCommand.cs b/ILSpy/Commands/OpenFromGacCommand.cs index c7fd898d0..ba65bfe21 100644 --- a/ILSpy/Commands/OpenFromGacCommand.cs +++ b/ILSpy/Commands/OpenFromGacCommand.cs @@ -43,7 +43,7 @@ namespace ICSharpCode.ILSpy public override void Execute(object parameter) { OpenFromGacDialog dlg = new OpenFromGacDialog { - Owner = MainWindow.Instance + Owner = App.Current.MainWindow }; if (dlg.ShowDialog() == true) diff --git a/ILSpy/Commands/Pdb2XmlCommand.cs b/ILSpy/Commands/Pdb2XmlCommand.cs index d4b9a7fae..14cfbeabe 100644 --- a/ILSpy/Commands/Pdb2XmlCommand.cs +++ b/ILSpy/Commands/Pdb2XmlCommand.cs @@ -26,6 +26,7 @@ using System.Threading.Tasks; using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.Decompiler; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TextView; 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)] [Shared] - sealed class Pdb2XmlCommand : SimpleCommand + sealed class Pdb2XmlCommand(AssemblyTreeModel assemblyTreeModel) : SimpleCommand { public override bool CanExecute(object parameter) { - var selectedNodes = MainWindow.Instance.AssemblyTreeModel.SelectedNodes; + var selectedNodes = assemblyTreeModel.SelectedNodes; return selectedNodes?.Any() == true && selectedNodes.All(n => n is AssemblyTreeNode asm && !asm.LoadedAssembly.HasLoadError); } 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) diff --git a/ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs b/ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs index 42673e99a..da67fd550 100644 --- a/ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs +++ b/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)] [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) { return assemblyTreeModel.AssemblyList.GetAssemblies().Any(l => l.HasLoadError); @@ -46,7 +39,7 @@ namespace ICSharpCode.ILSpy { if (!assembly.HasLoadError) continue; - var node = MainWindow.Instance.AssemblyTreeModel.FindAssemblyNode(assembly); + var node = assemblyTreeModel.FindAssemblyNode(assembly); if (node != null && node.CanDelete()) node.Delete(); } diff --git a/ILSpy/Commands/SaveCodeContextMenuEntry.cs b/ILSpy/Commands/SaveCodeContextMenuEntry.cs index 14f9fdf50..2dd646450 100644 --- a/ILSpy/Commands/SaveCodeContextMenuEntry.cs +++ b/ILSpy/Commands/SaveCodeContextMenuEntry.cs @@ -35,11 +35,11 @@ namespace ICSharpCode.ILSpy.TextView { [ExportContextMenuEntry(Header = nameof(Resources._SaveCode), Category = nameof(Resources.Save), Icon = "Images/Save")] [Shared] - sealed class SaveCodeContextMenuEntry : IContextMenuEntry + sealed class SaveCodeContextMenuEntry(LanguageService languageService) : IContextMenuEntry { public void Execute(TextViewContext context) { - Execute(context.SelectedTreeNodes); + Execute(context.SelectedTreeNodes, languageService); } 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))); } - 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 currentLanguage = LanguageService.Instance.Language; + var currentLanguage = languageService.Language; var tabPage = dockWorkspace.ActiveTabPage; tabPage.ShowTextView(textView => { 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. // try to save all nodes to disk. - var options = LanguageService.Instance.CreateDecompilationOptions(dockWorkspace.ActiveTabPage); + var options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions(); options.FullDecompilation = true; textView.SaveToDisk(currentLanguage, selectedNodes.OfType<ILSpyTreeNode>(), options); }); diff --git a/ILSpy/Commands/SaveCommand.cs b/ILSpy/Commands/SaveCommand.cs index 3b1927e21..3281df456 100644 --- a/ILSpy/Commands/SaveCommand.cs +++ b/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)] [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) { e.Handled = true; @@ -46,7 +38,7 @@ namespace ICSharpCode.ILSpy protected override void OnExecute(object sender, ExecutedRoutedEventArgs e) { - SaveCodeContextMenuEntry.Execute(assemblyTreeModel.SelectedNodes.ToList()); + SaveCodeContextMenuEntry.Execute(assemblyTreeModel.SelectedNodes.ToList(), languageService); } } } diff --git a/ILSpy/Commands/SelectPdbContextMenuEntry.cs b/ILSpy/Commands/SelectPdbContextMenuEntry.cs index e64ec3881..9c63a8b8c 100644 --- a/ILSpy/Commands/SelectPdbContextMenuEntry.cs +++ b/ILSpy/Commands/SelectPdbContextMenuEntry.cs @@ -21,6 +21,7 @@ using System.IO; using System.Linq; using ICSharpCode.Decompiler.CSharp.ProjectDecompiler; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TreeNodes; @@ -29,7 +30,7 @@ namespace ICSharpCode.ILSpy { [ExportContextMenuEntry(Header = nameof(Resources.SelectPDB))] [Shared] - class SelectPdbContextMenuEntry : IContextMenuEntry + class SelectPdbContextMenuEntry(AssemblyTreeModel assemblyTreeModel) : IContextMenuEntry { public async void Execute(TextViewContext context) { @@ -48,10 +49,10 @@ namespace ICSharpCode.ILSpy 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(); - MainWindow.Instance.AssemblyTreeModel.SelectNode(node); - MainWindow.Instance.AssemblyTreeModel.RefreshDecompiledView(); + assemblyTreeModel.SelectNode(node); + assemblyTreeModel.RefreshDecompiledView(); } public bool IsEnabled(TextViewContext context) => true; diff --git a/ILSpy/Commands/SetThemeCommand.cs b/ILSpy/Commands/SetThemeCommand.cs index 1f9a1226c..006faa107 100644 --- a/ILSpy/Commands/SetThemeCommand.cs +++ b/ILSpy/Commands/SetThemeCommand.cs @@ -1,13 +1,17 @@ +using System.Composition; + namespace ICSharpCode.ILSpy.Commands { - public class SetThemeCommand : SimpleCommand + [Export] + [Shared] + public class SetThemeCommand(SettingsService settingsService) : SimpleCommand { public override void Execute(object parameter) { if (parameter is string theme) { - SettingsService.Instance.SessionSettings.Theme = theme; + settingsService.SessionSettings.Theme = theme; } } } diff --git a/ILSpy/Commands/SortAssemblyListCommand.cs b/ILSpy/Commands/SortAssemblyListCommand.cs index f3a55682d..a9434f9c2 100644 --- a/ILSpy/Commands/SortAssemblyListCommand.cs +++ b/ILSpy/Commands/SortAssemblyListCommand.cs @@ -20,6 +20,7 @@ using System; using System.Collections.Generic; using System.Composition; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpyX; 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))] [ExportToolbarCommand(ToolTip = nameof(Resources.SortAssemblyListName), ToolbarIcon = "Images/Sort", ToolbarCategory = nameof(Resources.View))] [Shared] - sealed class SortAssemblyListCommand : SimpleCommand + sealed class SortAssemblyListCommand(AssemblyTreeModel assemblyTreeModel) : SimpleCommand { 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))] [ExportToolbarCommand(ToolTip = nameof(Resources.CollapseTreeNodes), ToolbarIcon = "Images/CollapseAll", ToolbarCategory = nameof(Resources.View))] [Shared] - sealed class CollapseAllCommand : SimpleCommand + sealed class CollapseAllCommand(AssemblyTreeModel assemblyTreeModel) : SimpleCommand { public override void Execute(object parameter) { - MainWindow.Instance.AssemblyTreeModel.CollapseAll(); + assemblyTreeModel.CollapseAll(); } } diff --git a/ILSpy/ContextMenuEntry.cs b/ILSpy/ContextMenuEntry.cs index 5d80ca5f1..1402a09b0 100644 --- a/ILSpy/ContextMenuEntry.cs +++ b/ILSpy/ContextMenuEntry.cs @@ -31,6 +31,7 @@ using ICSharpCode.ILSpyX.TreeView; using TomsToolbox.Composition; using TomsToolbox.Essentials; +using TomsToolbox.Wpf.Composition; namespace ICSharpCode.ILSpy { @@ -222,7 +223,7 @@ namespace ICSharpCode.ILSpy private ContextMenuProvider(Control control) { - entries = App.ExportProvider.GetExports<IContextMenuEntry, IContextMenuEntryMetadata>().ToArray(); + entries = control.GetExportProvider().GetExports<IContextMenuEntry, IContextMenuEntryMetadata>().ToArray(); this.control = control; } diff --git a/ILSpy/Docking/DockWorkspace.cs b/ILSpy/Docking/DockWorkspace.cs index b196f8e79..af59d3f59 100644 --- a/ILSpy/Docking/DockWorkspace.cs +++ b/ILSpy/Docking/DockWorkspace.cs @@ -32,6 +32,7 @@ using AvalonDock.Layout.Serialization; using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.ILSpy.Analyzers; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Search; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.ViewModels; @@ -44,15 +45,21 @@ namespace ICSharpCode.ILSpy.Docking { 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(); private readonly ObservableCollection<TabPageModel> tabPages = []; - private DockingManager dockingManager; + private DockingManager DockingManager => exportProvider.GetExportedValue<DockingManager>(); + + AssemblyTreeModel AssemblyTreeModel => exportProvider.GetExportedValue<AssemblyTreeModel>(); private DockWorkspace() { @@ -123,7 +130,7 @@ namespace ICSharpCode.ILSpy.Docking public void AddTabPage(TabPageModel tabPage = null) { - tabPages.Add(tabPage ?? new TabPageModel()); + tabPages.Add(tabPage ?? new TabPageModel(AssemblyTreeModel, SettingsService, LanguageService)); } public ReadOnlyObservableCollection<TabPageModel> TabPages { get; } @@ -170,29 +177,28 @@ namespace ICSharpCode.ILSpy.Docking { if (state.DecompiledNodes != null) { - MainWindow.Instance.AssemblyTreeModel.SelectNodes(state.DecompiledNodes); + AssemblyTreeModel.SelectNodes(state.DecompiledNodes); } else { - MainWindow.Instance.AssemblyTreeModel.NavigateTo(new(state.ViewedUri, null)); + AssemblyTreeModel.NavigateTo(new(state.ViewedUri, null)); } } } } public PaneModel ActivePane { - get => dockingManager?.ActiveContent as PaneModel; + get => DockingManager?.ActiveContent as PaneModel; set { - if (dockingManager is not null) - dockingManager.ActiveContent = value; + if (DockingManager is not null) + DockingManager.ActiveContent = value; } } - public void InitializeLayout(DockingManager manager) + public void InitializeLayout() { - this.dockingManager = manager; - manager.LayoutUpdateStrategy = this; - XmlLayoutSerializer serializer = new XmlLayoutSerializer(manager); + DockingManager.LayoutUpdateStrategy = this; + XmlLayoutSerializer serializer = new XmlLayoutSerializer(DockingManager); serializer.LayoutSerializationCallback += LayoutSerializationCallback; try { @@ -254,8 +260,8 @@ namespace ICSharpCode.ILSpy.Docking } CloseAllTabs(); SessionSettings.DockLayout.Reset(); - InitializeLayout(MainWindow.Instance.dockManager); - MainWindow.Instance.Dispatcher.BeginInvoke(DispatcherPriority.Background, (Action)MainWindow.Instance.AssemblyTreeModel.RefreshDecompiledView); + InitializeLayout(); + App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, AssemblyTreeModel.RefreshDecompiledView); } static readonly PropertyInfo previousContainerProperty = typeof(LayoutContent).GetProperty("PreviousContainer", BindingFlags.NonPublic | BindingFlags.Instance); diff --git a/ILSpy/ExtensionMethods.cs b/ILSpy/ExtensionMethods.cs index 1d49f41ad..bd460826c 100644 --- a/ILSpy/ExtensionMethods.cs +++ b/ILSpy/ExtensionMethods.cs @@ -76,10 +76,11 @@ namespace ICSharpCode.ILSpy return result; } - public static ICompilation? GetTypeSystemWithCurrentOptionsOrNull(this MetadataFile file) + public static ICompilation? GetTypeSystemWithCurrentOptionsOrNull(this MetadataFile file, SettingsService settingsService) { - return LoadedAssemblyExtensions.GetLoadedAssembly(file) - .GetTypeSystemOrNull(DecompilerTypeSystem.GetOptions(SettingsService.Instance.DecompilerSettings)); + return file + .GetLoadedAssembly() + .GetTypeSystemOrNull(DecompilerTypeSystem.GetOptions(settingsService.DecompilerSettings)); } #region DPI independence diff --git a/ILSpy/Languages/CSharpILMixedLanguage.cs b/ILSpy/Languages/CSharpILMixedLanguage.cs index 93752eaef..77ec68982 100644 --- a/ILSpy/Languages/CSharpILMixedLanguage.cs +++ b/ILSpy/Languages/CSharpILMixedLanguage.cs @@ -43,13 +43,13 @@ namespace ICSharpCode.ILSpy [Export(typeof(Language))] [Shared] - class CSharpILMixedLanguage : ILLanguage + class CSharpILMixedLanguage(SettingsService settingsService) : ILLanguage { public override string Name => "IL with C#"; protected override ReflectionDisassembler CreateDisassembler(ITextOutput output, DecompilationOptions options) { - var displaySettings = SettingsService.Instance.DisplaySettings; + var displaySettings = settingsService.DisplaySettings; return new ReflectionDisassembler(output, new MixedMethodBodyDisassembler(output, options) { DetectControlStructure = detectControlStructure, diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index 5725e0555..c59a3fec6 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -38,6 +38,7 @@ using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Output; using ICSharpCode.Decompiler.Solution; using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpyX; @@ -55,25 +56,18 @@ namespace ICSharpCode.ILSpy [Shared] public class CSharpLanguage : Language { - readonly IReadOnlyCollection<IResourceFileHandler> resourceFileHandlers; - string name = "C#"; bool showAllMembers = false; int transformCount = int.MaxValue; - public CSharpLanguage(IEnumerable<IResourceFileHandler> resourceFileHandlers) - { - this.resourceFileHandlers = resourceFileHandlers.ToArray(); - } - #if DEBUG - internal static IEnumerable<CSharpLanguage> GetDebugLanguages(IReadOnlyCollection<IResourceFileHandler> resourceFileHandlers) + internal static IEnumerable<CSharpLanguage> GetDebugLanguages() { string lastTransformName = "no transforms"; int transformCount = 0; foreach (var transform in CSharpDecompiler.GetAstTransforms()) { - yield return new CSharpLanguage(resourceFileHandlers) { + yield return new() { transformCount = transformCount, name = "C# - " + lastTransformName, showAllMembers = true @@ -81,7 +75,7 @@ namespace ICSharpCode.ILSpy lastTransformName = "after " + transform.GetType().Name; transformCount++; } - yield return new CSharpLanguage(resourceFileHandlers) { + yield return new() { name = "C# - " + lastTransformName, showAllMembers = true }; @@ -364,15 +358,15 @@ namespace ICSharpCode.ILSpy 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) return; string line1 = Properties.Resources.WarningSomeAssemblyReference; string line2 = Properties.Resources.PropertyManuallyMissingReferencesListLoadedAssemblies; 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(); - 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; } - var decompiler = new ILSpyWholeProjectDecompiler(assembly, options, resourceFileHandlers) { + var decompiler = new ILSpyWholeProjectDecompiler(assembly, options) { ProgressIndicator = options.Progress }; return decompiler.DecompileProject(module, options.SaveAsProjectDirectory, new TextOutputWriter(output), options.CancellationToken); @@ -549,20 +543,18 @@ namespace ICSharpCode.ILSpy { readonly LoadedAssembly assembly; 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()) { this.assembly = assembly; this.options = options; - this.resourceFileHandlers = resourceFileHandlers; } protected override IEnumerable<ProjectItemInfo> WriteResourceToFile(string fileName, string resourceName, Stream entryStream) { var context = new ResourceFileHandlerContext(options); - foreach (var handler in resourceFileHandlers) + foreach (var handler in ResourceFileHandlers) { if (handler.CanHandle(fileName, context)) { @@ -576,19 +568,19 @@ namespace ICSharpCode.ILSpy } } - static CSharpAmbience CreateAmbience() + CSharpAmbience CreateAmbience() { CSharpAmbience ambience = new CSharpAmbience(); // Do not forget to update CSharpAmbienceTests.ILSpyMainTreeViewTypeFlags, if this ever changes. ambience.ConversionFlags = ConversionFlags.ShowTypeParameterList | ConversionFlags.PlaceReturnTypeAfterParameterList; - if (SettingsService.Instance.DecompilerSettings.LiftNullables) + if (SettingsService.DecompilerSettings.LiftNullables) { ambience.ConversionFlags |= ConversionFlags.UseNullableSpecifierForValueTypes; } 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. var ambience = CreateAmbience(); @@ -784,7 +776,7 @@ namespace ICSharpCode.ILSpy public override bool ShowMember(IEntity member) { 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) @@ -793,7 +785,7 @@ namespace ICSharpCode.ILSpy var output = new StringWriter(); var decoratedWriter = new TextWriterTokenWriter(output); var writer = new CSharpHighlightingTokenWriter(TokenWriter.InsertRequiredSpaces(decoratedWriter), locatable: decoratedWriter); - var settings = SettingsService.Instance.DecompilerSettings; + var settings = SettingsService.DecompilerSettings; if (!settings.LiftNullables) { flags &= ~ConversionFlags.UseNullableSpecifierForValueTypes; diff --git a/ILSpy/Languages/ILLanguage.cs b/ILSpy/Languages/ILLanguage.cs index a857268f1..31494f7d8 100644 --- a/ILSpy/Languages/ILLanguage.cs +++ b/ILSpy/Languages/ILLanguage.cs @@ -31,6 +31,7 @@ using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.Util; using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.TextView; +using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpyX; namespace ICSharpCode.ILSpy @@ -58,7 +59,7 @@ namespace ICSharpCode.ILSpy protected virtual ReflectionDisassembler CreateDisassembler(ITextOutput output, DecompilationOptions options) { - var displaySettings = SettingsService.Instance.DisplaySettings; + var displaySettings = SettingsService.DisplaySettings; output.IndentationString = options.DecompilerSettings.CSharpFormattingOptions.IndentationString; return new ReflectionDisassembler(output, options.CancellationToken) { DetectControlStructure = detectControlStructure, @@ -198,10 +199,9 @@ namespace ICSharpCode.ILSpy public override RichText GetRichTextTooltip(IEntity entity) { var output = new AvalonEditTextOutput() { IgnoreNewLineAndIndent = true }; - var settingsService = SettingsService.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; if (module == null) { diff --git a/ILSpy/Languages/Language.cs b/ILSpy/Languages/Language.cs index 26410fe24..59511f9cb 100644 --- a/ILSpy/Languages/Language.cs +++ b/ILSpy/Languages/Language.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; using System.Text; @@ -29,6 +30,7 @@ using ICSharpCode.Decompiler.Solution; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.Util; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX.Abstractions; @@ -42,6 +44,12 @@ namespace ICSharpCode.ILSpy /// </remarks> 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> /// Gets the name of the language (as shown in the UI) /// </summary> diff --git a/ILSpy/Languages/LanguageService.cs b/ILSpy/Languages/LanguageService.cs index e060c117d..f5282853c 100644 --- a/ILSpy/Languages/LanguageService.cs +++ b/ILSpy/Languages/LanguageService.cs @@ -21,26 +21,23 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Composition; using System.Linq; -using ICSharpCode.Decompiler; -using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpyX; using TomsToolbox.Wpf; namespace ICSharpCode.ILSpy { + [Export] + [Shared] 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 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; var sortedLanguages = languages.ToList(); @@ -48,7 +45,7 @@ namespace ICSharpCode.ILSpy sortedLanguages.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.Ordinal)); #if DEBUG sortedLanguages.AddRange(ILAstLanguage.GetDebugLanguages()); - sortedLanguages.AddRange(CSharpLanguage.GetDebugLanguages(resourceFileHandlers.ToArray())); + sortedLanguages.AddRange(CSharpLanguage.GetDebugLanguages()); #endif AllLanguages = sortedLanguages.AsReadOnly(); @@ -143,10 +140,5 @@ namespace ICSharpCode.ILSpy languageSettings.LanguageVersionId = languageVersion?.Version; } } - - public DecompilationOptions CreateDecompilationOptions(TabPageModel tabPage) - { - return new(LanguageVersion, settingsService.DecompilerSettings, settingsService.DisplaySettings) { Progress = tabPage.Content as IProgress<DecompilationProgress> }; - } } } diff --git a/ILSpy/MainWindow.xaml b/ILSpy/MainWindow.xaml index bbefc63fc..2aece0f63 100644 --- a/ILSpy/MainWindow.xaml +++ b/ILSpy/MainWindow.xaml @@ -18,6 +18,8 @@ xmlns:themes="clr-namespace:ICSharpCode.ILSpy.Themes" xmlns:toms="urn:TomsToolbox" 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}"> <Window.Resources> @@ -36,7 +38,7 @@ </b:Interaction.Behaviors> <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}" /> </Window.InputBindings> @@ -60,7 +62,7 @@ <MenuItem Header="{x:Static properties:Resources.Theme}" ItemsSource="{x:Static themes:ThemeManager.AllThemes}"> <MenuItem.ItemContainerStyle> <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="IsCheckable" Value="True" /> <!-- Required by AvalonDock's MenuItem style to show the checkmark --> @@ -123,7 +125,7 @@ ToolTip="{x:Static properties:Resources.SelectAssemblyListDropdownTooltip}" SelectedItem="{Binding SessionSettings.ActiveAssemblyList}" /> </Grid> - <Button Command="{x:Static local:ILSpyCommands.ManageAssemblyListsCommand}" + <Button Command="{composition:Import {x:Type local:ManageAssemblyListsCommand}}" ToolTip="{x:Static properties:Resources.ManageAssemblyLists}"> <Image Width="16" Height="16" Source="{controls:XamlResource Images/AssemblyList}" Style="{StaticResource DarkModeAwareImageStyle}" /> @@ -186,7 +188,7 @@ </StatusBarItem> </StatusBar> - <avalondock:DockingManager x:Name="dockManager" + <avalondock:DockingManager x:Name="DockManager" DataContext="{Binding Workspace}" AnchorablesSource="{Binding ToolPanes}" DocumentsSource="{Binding TabPages}" diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 981da03e8..e9d392717 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -17,7 +17,9 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections.Generic; using System.ComponentModel; +using System.Composition; using System.Diagnostics; using System.Drawing; using System.Linq; @@ -30,7 +32,6 @@ using System.Windows.Threading; using AvalonDock.Layout.Serialization; using ICSharpCode.ILSpy.AssemblyTree; -using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.Updates; using ICSharpCode.ILSpyX.FileLoaders; @@ -44,25 +45,22 @@ namespace ICSharpCode.ILSpy /// <summary> /// The main window of the application. /// </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 static MainWindow Instance { - get { return instance; } - } - - public AssemblyTreeModel AssemblyTreeModel { - get { - return App.ExportProvider.GetExportedValue<AssemblyTreeModel>(); - } - } - - public MainWindow() + public MainWindow(MainWindowViewModel mainWindowViewModel, AssemblyTreeModel assemblyTreeModel, IEnumerable<IFileLoader> fileLoaders, MenuService menuService, SettingsService settingsService) { - instance = this; + this.assemblyTreeModel = assemblyTreeModel; + this.fileLoaders = fileLoaders; + this.menuService = menuService; + this.settingsService = settingsService; // Make sure Images are initialized on the UI thread. this.Icon = Images.ILSpyIcon; @@ -74,12 +72,12 @@ namespace ICSharpCode.ILSpy InitFileLoaders(); Dispatcher.BeginInvoke(DispatcherPriority.Background, () => { - mainWindowViewModel.Workspace.InitializeLayout(dockManager); - MenuService.Instance.Init(mainMenu, toolBar, InputBindings); + mainWindowViewModel.Workspace.InitializeLayout(); + menuService.Init(mainMenu, toolBar, InputBindings); Dispatcher.BeginInvoke(DispatcherPriority.Background, () => { - AssemblyTreeModel.Initialize(); - AssemblyTreeModel.Show(); + assemblyTreeModel.Initialize(); + assemblyTreeModel.Show(); }); }); } @@ -97,9 +95,8 @@ namespace ICSharpCode.ILSpy void InitFileLoaders() { // 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 sessionSettings = SettingsService.Instance.SessionSettings; + var sessionSettings = settingsService.SessionSettings; // Validate and Set Window Bounds var windowBounds = Rect.Transform(sessionSettings.WindowBounds, source?.CompositionTarget?.TransformToDevice ?? Matrix.Identity); @@ -185,7 +182,7 @@ namespace ICSharpCode.ILSpy else { updatePanel.Visibility = Visibility.Collapsed; - string downloadUrl = await NotifyOfUpdatesStrategy.CheckForUpdatesAsync(SettingsService.Instance.SpySettings); + string downloadUrl = await NotifyOfUpdatesStrategy.CheckForUpdatesAsync(settingsService.SpySettings); AdjustUpdateUIAfterCheck(downloadUrl, true); } } @@ -243,22 +240,22 @@ namespace ICSharpCode.ILSpy base.OnStateChanged(e); // store window state in settings only if it's not minimized if (this.WindowState != WindowState.Minimized) - SettingsService.Instance.SessionSettings.WindowState = this.WindowState; + settingsService.SessionSettings.WindowState = this.WindowState; } protected override void OnClosing(CancelEventArgs e) { base.OnClosing(e); - var snapshot = SettingsService.Instance.CreateSnapshot(); + var snapshot = settingsService.CreateSnapshot(); var sessionSettings = snapshot.GetSettings<SessionSettings>(); - sessionSettings.ActiveAssemblyList = AssemblyTreeModel.AssemblyList.ListName; - sessionSettings.ActiveTreeViewPath = AssemblyTreeModel.SelectedPath; - sessionSettings.ActiveAutoLoadedAssembly = GetAutoLoadedAssemblyNode(AssemblyTreeModel.SelectedItem); + sessionSettings.ActiveAssemblyList = assemblyTreeModel.AssemblyList.ListName; + sessionSettings.ActiveTreeViewPath = assemblyTreeModel.SelectedPath; + sessionSettings.ActiveAutoLoadedAssembly = GetAutoLoadedAssemblyNode(assemblyTreeModel.SelectedItem); sessionSettings.WindowBounds = this.RestoreBounds; - sessionSettings.DockLayout.Serialize(new XmlLayoutSerializer(dockManager)); + sessionSettings.DockLayout.Serialize(new XmlLayoutSerializer(DockManager)); snapshot.Save(); } diff --git a/ILSpy/MainWindowViewModel.cs b/ILSpy/MainWindowViewModel.cs index 8611f3189..b5f22165d 100644 --- a/ILSpy/MainWindowViewModel.cs +++ b/ILSpy/MainWindowViewModel.cs @@ -16,6 +16,10 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using System.Composition; + +using ICSharpCode.ILSpy.Analyzers; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpyX; @@ -23,11 +27,15 @@ using TomsToolbox.Wpf; 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 SessionSettings SessionSettings => SettingsService.Instance.SessionSettings; - public LanguageService LanguageService => LanguageService.Instance; - public AssemblyListManager AssemblyListManager => SettingsService.Instance.AssemblyListManager; + public SessionSettings SessionSettings => settingsService.SessionSettings; + public LanguageService LanguageService => languageService; + public AssemblyListManager AssemblyListManager => settingsService.AssemblyListManager; + + public AnalyzeCommand AnalyzeCommand { get; } = new(assemblyTreeModel, analyzerTreeViewModel); } } diff --git a/ILSpy/Metadata/CorTables/EventTableTreeNode.cs b/ILSpy/Metadata/CorTables/EventTableTreeNode.cs index 14dabb3e0..821a25476 100644 --- a/ILSpy/Metadata/CorTables/EventTableTreeNode.cs +++ b/ILSpy/Metadata/CorTables/EventTableTreeNode.cs @@ -94,7 +94,7 @@ namespace ICSharpCode.ILSpy.Metadata IEntity IMemberTreeNode.Member { get { - return ((MetadataModule)metadataFile.GetTypeSystemWithCurrentOptionsOrNull()?.MainModule)?.GetDefinition(handle); + return ((MetadataModule)metadataFile.GetTypeSystemWithCurrentOptionsOrNull(SettingsService)?.MainModule)?.GetDefinition(handle); } } diff --git a/ILSpy/Metadata/CorTables/FieldTableTreeNode.cs b/ILSpy/Metadata/CorTables/FieldTableTreeNode.cs index c8e8e310d..eb48eaec2 100644 --- a/ILSpy/Metadata/CorTables/FieldTableTreeNode.cs +++ b/ILSpy/Metadata/CorTables/FieldTableTreeNode.cs @@ -95,7 +95,7 @@ namespace ICSharpCode.ILSpy.Metadata 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)] public int Signature => MetadataTokens.GetHeapOffset(fieldDef.Signature); diff --git a/ILSpy/Metadata/CorTables/MethodTableTreeNode.cs b/ILSpy/Metadata/CorTables/MethodTableTreeNode.cs index cfea5f2ae..775661855 100644 --- a/ILSpy/Metadata/CorTables/MethodTableTreeNode.cs +++ b/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) { diff --git a/ILSpy/Metadata/CorTables/PropertyTableTreeNode.cs b/ILSpy/Metadata/CorTables/PropertyTableTreeNode.cs index 05ff38b71..255892ea1 100644 --- a/ILSpy/Metadata/CorTables/PropertyTableTreeNode.cs +++ b/ILSpy/Metadata/CorTables/PropertyTableTreeNode.cs @@ -92,7 +92,7 @@ namespace ICSharpCode.ILSpy.Metadata 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)] public int Signature => MetadataTokens.GetHeapOffset(propertyDef.Signature); diff --git a/ILSpy/Metadata/CorTables/TypeDefTableTreeNode.cs b/ILSpy/Metadata/CorTables/TypeDefTableTreeNode.cs index 129f76907..e7aa7bbd4 100644 --- a/ILSpy/Metadata/CorTables/TypeDefTableTreeNode.cs +++ b/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) { diff --git a/ILSpy/Metadata/DebugMetadataTablesTreeNode.cs b/ILSpy/Metadata/DebugMetadataTablesTreeNode.cs index d3067d713..6fcbd7dc0 100644 --- a/ILSpy/Metadata/DebugMetadataTablesTreeNode.cs +++ b/ILSpy/Metadata/DebugMetadataTablesTreeNode.cs @@ -58,7 +58,7 @@ namespace ICSharpCode.ILSpy.Metadata if (ShowTable(TableIndex.CustomDebugInformation)) 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) diff --git a/ILSpy/Metadata/MetadataProtocolHandler.cs b/ILSpy/Metadata/MetadataProtocolHandler.cs index c3ffae68e..61cb28a36 100644 --- a/ILSpy/Metadata/MetadataProtocolHandler.cs +++ b/ILSpy/Metadata/MetadataProtocolHandler.cs @@ -21,20 +21,21 @@ using System.Linq; using System.Reflection.Metadata; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.TreeNodes; namespace ICSharpCode.ILSpy.Metadata { [Export(typeof(IProtocolHandler))] [Shared] - class MetadataProtocolHandler : IProtocolHandler + class MetadataProtocolHandler(AssemblyTreeModel assemblyTreeModel) : IProtocolHandler { public ILSpyTreeNode Resolve(string protocol, MetadataFile module, Handle handle, out bool newTabPage) { newTabPage = true; if (protocol != "metadata") return null; - var assemblyTreeNode = MainWindow.Instance.AssemblyTreeModel.FindTreeNode(module) as AssemblyTreeNode; + var assemblyTreeNode = assemblyTreeModel.FindTreeNode(module) as AssemblyTreeNode; if (assemblyTreeNode == null) return null; var mxNode = assemblyTreeNode.Children.OfType<MetadataTreeNode>().FirstOrDefault(); diff --git a/ILSpy/Metadata/MetadataTablesTreeNode.cs b/ILSpy/Metadata/MetadataTablesTreeNode.cs index 1fb55be81..c40868120 100644 --- a/ILSpy/Metadata/MetadataTablesTreeNode.cs +++ b/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) { diff --git a/ILSpy/Options/OptionsDialog.xaml.cs b/ILSpy/Options/OptionsDialog.xaml.cs index 1e56f8683..aa596a1d7 100644 --- a/ILSpy/Options/OptionsDialog.xaml.cs +++ b/ILSpy/Options/OptionsDialog.xaml.cs @@ -29,9 +29,9 @@ namespace ICSharpCode.ILSpy.Options /// </summary> public sealed partial class OptionsDialog { - public OptionsDialog() + public OptionsDialog(SettingsService settingsService) { - DataContext = new OptionsDialogViewModel(); + DataContext = new OptionsDialogViewModel(settingsService); InitializeComponent(); } } @@ -59,19 +59,12 @@ namespace ICSharpCode.ILSpy.Options [ExportMainMenuCommand(ParentMenuID = nameof(Resources._View), Header = nameof(Resources._Options), MenuCategory = nameof(Resources.Options), MenuOrder = 999)] [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) { - OptionsDialog dlg = new() { - Owner = MainWindow.Instance, + OptionsDialog dlg = new(settingsService) { + Owner = App.Current.MainWindow, }; if (dlg.ShowDialog() == true) { diff --git a/ILSpy/Options/OptionsDialogViewModel.cs b/ILSpy/Options/OptionsDialogViewModel.cs index 0a82d2357..22cfd0100 100644 --- a/ILSpy/Options/OptionsDialogViewModel.cs +++ b/ILSpy/Options/OptionsDialogViewModel.cs @@ -46,9 +46,9 @@ namespace ICSharpCode.ILSpy.Options .ExceptNullItems() .ToArray(); - public OptionsDialogViewModel() + public OptionsDialogViewModel(SettingsService settingsService) { - this.snapshot = SettingsService.Instance.CreateSnapshot(); + this.snapshot = settingsService.CreateSnapshot(); foreach (var optionPage in optionPages) { diff --git a/ILSpy/Search/SearchPane.xaml.cs b/ILSpy/Search/SearchPane.xaml.cs index 2702dac2f..9cd20e370 100644 --- a/ILSpy/Search/SearchPane.xaml.cs +++ b/ILSpy/Search/SearchPane.xaml.cs @@ -33,9 +33,11 @@ using System.Windows.Media; using System.Windows.Threading; using ICSharpCode.ILSpy.AppEnv; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpyX; +using ICSharpCode.ILSpyX.Abstractions; using ICSharpCode.ILSpyX.Extensions; using ICSharpCode.ILSpyX.Search; @@ -57,13 +59,20 @@ namespace ICSharpCode.ILSpy.Search RunningSearch currentSearch; bool runSearchOnNextShow; IComparer<SearchResult> resultsComparer; + readonly AssemblyTreeModel assemblyTreeModel; + readonly ITreeNodeFactory treeNodeFactory; + readonly SettingsService settingsService; public ObservableCollection<SearchResult> Results { get; } = []; string SearchTerm => searchBox.Text; - public SearchPane() + public SearchPane(AssemblyTreeModel assemblyTreeModel, ITreeNodeFactory treeNodeFactory, SettingsService settingsService) { + this.assemblyTreeModel = assemblyTreeModel; + this.treeNodeFactory = treeNodeFactory; + this.settingsService = settingsService; + InitializeComponent(); ContextMenuProvider.Add(listBox); @@ -214,7 +223,7 @@ namespace ICSharpCode.ILSpy.Search var timer = Stopwatch.StartNew(); 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); ++resultsAdded; @@ -243,8 +252,7 @@ namespace ICSharpCode.ILSpy.Search currentSearch = null; } - MainWindow mainWindow = MainWindow.Instance; - resultsComparer = SettingsService.Instance.DisplaySettings.SortResults ? + resultsComparer = settingsService.DisplaySettings.SortResults ? SearchResult.ComparerByFitness : SearchResult.ComparerByName; Results.Clear(); @@ -254,9 +262,12 @@ namespace ICSharpCode.ILSpy.Search { searchProgressBar.IsIndeterminate = true; - startedSearch = new(await mainWindow.AssemblyTreeModel.AssemblyList.GetAllAssemblies(), searchTerm, - (SearchMode)searchModeComboBox.SelectedIndex, mainWindow.AssemblyTreeModel.CurrentLanguage, - SettingsService.Instance.SessionSettings.LanguageSettings.ShowApiLevel); + startedSearch = new(await assemblyTreeModel.AssemblyList.GetAllAssemblies(), + searchTerm, + (SearchMode)searchModeComboBox.SelectedIndex, + assemblyTreeModel.CurrentLanguage, + treeNodeFactory, + settingsService); currentSearch = startedSearch; await startedSearch.Run(); @@ -285,15 +296,20 @@ namespace ICSharpCode.ILSpy.Search readonly SearchMode searchMode; readonly Language language; 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, - Language language, ApiVisibility apiVisibility) + Language language, ITreeNodeFactory treeNodeFactory, SettingsService settingsService) { this.assemblies = assemblies; this.language = language; this.searchMode = searchMode; - this.apiVisibility = apiVisibility; + this.apiVisibility = settingsService.SessionSettings.LanguageSettings.ShowApiLevel; + this.treeNodeFactory = treeNodeFactory; + this.settingsService = settingsService; this.searchRequest = Parse(searchTerm); } @@ -454,8 +470,8 @@ namespace ICSharpCode.ILSpy.Search request.Keywords = keywords.ToArray(); request.RegEx = regex; request.SearchResultFactory = new SearchResultFactory(language); - request.TreeNodeFactory = new TreeNodeFactory(); - request.DecompilerSettings = SettingsService.Instance.DecompilerSettings; + request.TreeNodeFactory = this.treeNodeFactory; + request.DecompilerSettings = settingsService.DecompilerSettings; return request; } @@ -504,29 +520,29 @@ namespace ICSharpCode.ILSpy.Search switch (request.Mode) { case SearchMode.TypeAndMember: - return new MemberSearchStrategy(language, apiVisibility, request, resultQueue); + return new MemberSearchStrategy(language, apiVisibility, request, ResultQueue); case SearchMode.Type: - return new MemberSearchStrategy(language, apiVisibility, request, resultQueue, MemberSearchKind.Type); + return new MemberSearchStrategy(language, apiVisibility, request, ResultQueue, MemberSearchKind.Type); case SearchMode.Member: - return new MemberSearchStrategy(language, apiVisibility, request, resultQueue, request.MemberSearchKind); + return new MemberSearchStrategy(language, apiVisibility, request, ResultQueue, request.MemberSearchKind); case SearchMode.Literal: - return new LiteralSearchStrategy(language, apiVisibility, request, resultQueue); + return new LiteralSearchStrategy(language, apiVisibility, request, ResultQueue); case SearchMode.Method: - return new MemberSearchStrategy(language, apiVisibility, request, resultQueue, MemberSearchKind.Method); + return new MemberSearchStrategy(language, apiVisibility, request, ResultQueue, MemberSearchKind.Method); case SearchMode.Field: - return new MemberSearchStrategy(language, apiVisibility, request, resultQueue, MemberSearchKind.Field); + return new MemberSearchStrategy(language, apiVisibility, request, ResultQueue, MemberSearchKind.Field); case SearchMode.Property: - return new MemberSearchStrategy(language, apiVisibility, request, resultQueue, MemberSearchKind.Property); + return new MemberSearchStrategy(language, apiVisibility, request, ResultQueue, MemberSearchKind.Property); case SearchMode.Event: - return new MemberSearchStrategy(language, apiVisibility, request, resultQueue, MemberSearchKind.Event); + return new MemberSearchStrategy(language, apiVisibility, request, ResultQueue, MemberSearchKind.Event); case SearchMode.Token: - return new MetadataTokenSearchStrategy(language, apiVisibility, request, resultQueue); + return new MetadataTokenSearchStrategy(language, apiVisibility, request, ResultQueue); case SearchMode.Resource: - return new ResourceSearchStrategy(apiVisibility, request, resultQueue); + return new ResourceSearchStrategy(apiVisibility, request, ResultQueue); case SearchMode.Assembly: - return new AssemblySearchStrategy(request, resultQueue, AssemblySearchKind.NameOrFileName); + return new AssemblySearchStrategy(request, ResultQueue, AssemblySearchKind.NameOrFileName); case SearchMode.Namespace: - return new NamespaceSearchStrategy(request, resultQueue); + return new NamespaceSearchStrategy(request, ResultQueue); } return null; diff --git a/ILSpy/Search/SearchPaneModel.cs b/ILSpy/Search/SearchPaneModel.cs index d598c0359..5d3988822 100644 --- a/ILSpy/Search/SearchPaneModel.cs +++ b/ILSpy/Search/SearchPaneModel.cs @@ -37,11 +37,14 @@ namespace ICSharpCode.ILSpy.Search [Export] public class SearchPaneModel : ToolPaneModel { - private string searchTerm; public const string PaneContentId = "searchPane"; - public SearchPaneModel() + private readonly SettingsService settingsService; + private string searchTerm; + + public SearchPaneModel(SettingsService settingsService) { + this.settingsService = settingsService; ContentId = PaneContentId; Title = Properties.Resources.SearchPane_Search; Icon = "Images/Search"; @@ -64,7 +67,7 @@ namespace ICSharpCode.ILSpy.Search new() { Mode = SearchMode.Namespace, Image = Images.Namespace, Name = "Namespace" } ]; - public SessionSettings SessionSettings => SettingsService.Instance.SessionSettings; + public SessionSettings SessionSettings => settingsService.SessionSettings; public string SearchTerm { get => searchTerm; diff --git a/ILSpy/Search/SearchResultFactory.cs b/ILSpy/Search/SearchResultFactory.cs index f466436c7..e81c23402 100644 --- a/ILSpy/Search/SearchResultFactory.cs +++ b/ILSpy/Search/SearchResultFactory.cs @@ -16,6 +16,8 @@ // 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.Composition; using System.Windows.Media; using ICSharpCode.Decompiler.Metadata; @@ -158,6 +160,8 @@ namespace ICSharpCode.ILSpy.Search } } + [Export(typeof(ITreeNodeFactory))] + [Shared] internal class TreeNodeFactory : ITreeNodeFactory { public ITreeNode Create(Resource resource) diff --git a/ILSpy/SolutionWriter.cs b/ILSpy/SolutionWriter.cs index ca36873fb..ff0035330 100644 --- a/ILSpy/SolutionWriter.cs +++ b/ILSpy/SolutionWriter.cs @@ -30,6 +30,7 @@ using ICSharpCode.Decompiler.Solution; using ICSharpCode.Decompiler.Util; using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.TextView; +using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpyX; namespace ICSharpCode.ILSpy @@ -213,7 +214,7 @@ namespace ICSharpCode.ILSpy using (var projectFileWriter = new StreamWriter(projectFileName)) { var projectFileOutput = new PlainTextOutput(projectFileWriter); - var options = LanguageService.Instance.CreateDecompilationOptions(DockWorkspace.Instance.ActiveTabPage); + var options = DockWorkspace.Instance.ActiveTabPage.CreateDecompilationOptions(); options.FullDecompilation = true; options.CancellationToken = ct; options.SaveAsProjectDirectory = targetDirectory; diff --git a/ILSpy/TaskHelper.cs b/ILSpy/TaskHelper.cs index 5b33bff3c..58b2ed1f6 100644 --- a/ILSpy/TaskHelper.cs +++ b/ILSpy/TaskHelper.cs @@ -197,7 +197,7 @@ namespace ICSharpCode.ILSpy /// </summary> 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(); output.Write(exception.ToString()); Docking.DockWorkspace.Instance.ShowText(output); diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index dc54ddc08..efd21d60c 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -74,6 +74,9 @@ namespace ICSharpCode.ILSpy.TextView /// </summary> public sealed partial class DecompilerTextView : UserControl, IHaveState, IProgress<DecompilationProgress> { + readonly AssemblyTreeModel assemblyTreeModel; + readonly SettingsService settingsService; + private readonly LanguageService languageService; readonly ReferenceElementGenerator referenceElementGenerator; readonly UIElementGenerator uiElementGenerator; readonly List<VisualLineElementGenerator?> activeCustomElementGenerators = new List<VisualLineElementGenerator?>(); @@ -94,8 +97,12 @@ namespace ICSharpCode.ILSpy.TextView readonly List<ITextMarker> localReferenceMarks = new List<ITextMarker>(); #region Constructor - public DecompilerTextView() + public DecompilerTextView(TabPageModel tabPage) { + this.assemblyTreeModel = tabPage.AssemblyTreeModel; + this.settingsService = tabPage.SettingsService; + this.languageService = tabPage.LanguageService; + RegisterHighlighting(); InitializeComponent(); @@ -113,9 +120,9 @@ namespace ICSharpCode.ILSpy.TextView textEditor.TextArea.Caret.PositionChanged += HighlightBrackets; textEditor.MouseMove += TextEditorMouseMove; textEditor.MouseLeave += TextEditorMouseLeave; - textEditor.SetBinding(Control.FontFamilyProperty, new Binding { Source = SettingsService.Instance.DisplaySettings, Path = new PropertyPath("SelectedFont") }); - textEditor.SetBinding(Control.FontSizeProperty, new Binding { Source = SettingsService.Instance.DisplaySettings, Path = new PropertyPath("SelectedFontSize") }); - textEditor.SetBinding(TextEditor.WordWrapProperty, new Binding { Source = SettingsService.Instance.DisplaySettings, Path = new PropertyPath("EnableWordWrap") }); + textEditor.SetBinding(Control.FontFamilyProperty, new Binding { Source = settingsService.DisplaySettings, Path = new PropertyPath("SelectedFont") }); + textEditor.SetBinding(Control.FontSizeProperty, new Binding { Source = settingsService.DisplaySettings, Path = new PropertyPath("SelectedFontSize") }); + 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 RemoveEditCommand(EditingCommands.TabForward); @@ -130,7 +137,7 @@ namespace ICSharpCode.ILSpy.TextView // SearchPanel 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.Loaded += (_, _) => { // HACK: fix search text box @@ -207,14 +214,14 @@ namespace ICSharpCode.ILSpy.TextView { 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() { - textEditor.Options.HighlightCurrentLine = SettingsService.Instance.DisplaySettings.HighlightCurrentLine; + textEditor.Options.HighlightCurrentLine = settingsService.DisplaySettings.HighlightCurrentLine; } #endregion @@ -400,10 +407,12 @@ namespace ICSharpCode.ILSpy.TextView object? GenerateTooltip(ReferenceSegment segment) { + var fontSize = settingsService.DisplaySettings.SelectedFontSize; + if (segment.Reference is ICSharpCode.Decompiler.Disassembler.OpCodeInfo code) { 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})"); if (docProvider != null) { @@ -413,18 +422,18 @@ namespace ICSharpCode.ILSpy.TextView renderer.AddXmlDocumentation(documentation, null, null); } } - return new FlowDocumentTooltip(renderer.CreateDocument()); + return new FlowDocumentTooltip(renderer.CreateDocument(), fontSize); } else if (segment.Reference is IEntity entity) { var document = CreateTooltipForEntity(entity); if (document == null) return null; - return new FlowDocumentTooltip(document); + return new FlowDocumentTooltip(document, fontSize); } else if (segment.Reference is EntityReference unresolvedEntity) { - var module = unresolvedEntity.ResolveAssembly(MainWindow.Instance.AssemblyTreeModel.AssemblyList); + var module = unresolvedEntity.ResolveAssembly(assemblyTreeModel.AssemblyList); if (module == null) return null; var typeSystem = new DecompilerTypeSystem(module, @@ -441,7 +450,7 @@ namespace ICSharpCode.ILSpy.TextView var document = CreateTooltipForEntity(resolved); if (document == null) return null; - return new FlowDocumentTooltip(document); + return new FlowDocumentTooltip(document, fontSize); } catch (BadImageFormatException) { @@ -451,10 +460,10 @@ namespace ICSharpCode.ILSpy.TextView return null; } - static FlowDocument? CreateTooltipForEntity(IEntity resolved) + FlowDocument? CreateTooltipForEntity(IEntity resolved) { - Language currentLanguage = LanguageService.Instance.Language; - DocumentationUIBuilder renderer = new DocumentationUIBuilder(new CSharpAmbience(), currentLanguage.SyntaxHighlighting); + Language currentLanguage = languageService.Language; + DocumentationUIBuilder renderer = new DocumentationUIBuilder(new CSharpAmbience(), currentLanguage.SyntaxHighlighting, settingsService.DisplaySettings); RichText richText = currentLanguage.GetRichTextTooltip(resolved); if (richText == null) { @@ -484,7 +493,7 @@ namespace ICSharpCode.ILSpy.TextView 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; - public FlowDocumentTooltip(FlowDocument document) + public FlowDocumentTooltip(FlowDocument document, double fontSize) { TextOptions.SetTextFormattingMode(this, TextFormattingMode.Display); - double fontSize = SettingsService.Instance.DisplaySettings.SelectedFontSize; viewer = new FlowDocumentScrollViewer() { Width = document.MinPageWidth + fontSize * 5, - MaxWidth = MainWindow.Instance.ActualWidth + MaxWidth = App.Current.MainWindow.ActualWidth }; viewer.Document = document; Border border = new Border { @@ -542,9 +550,9 @@ namespace ICSharpCode.ILSpy.TextView #region Highlight brackets 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); } else @@ -564,7 +572,7 @@ namespace ICSharpCode.ILSpy.TextView progressTitle.Text = !string.IsNullOrWhiteSpace(value.Title) ? value.Title : Properties.Resources.Decompiling; progressText.Text = value.Status; progressText.Visibility = !string.IsNullOrWhiteSpace(progressText.Text) ? Visibility.Visible : Visibility.Collapsed; - var taskBar = MainWindow.Instance.TaskbarItemInfo; + var taskBar = App.Current.MainWindow.TaskbarItemInfo; if (taskBar != null) { taskBar.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Normal; @@ -594,7 +602,7 @@ namespace ICSharpCode.ILSpy.TextView progressText.Text = null; progressText.Visibility = Visibility.Collapsed; 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) { taskBar.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Indeterminate; @@ -633,7 +641,7 @@ namespace ICSharpCode.ILSpy.TextView progressBar.IsIndeterminate = false; progressText.Text = null; progressText.Visibility = Visibility.Collapsed; - var taskBar = MainWindow.Instance.TaskbarItemInfo; + var taskBar = App.Current.MainWindow.TaskbarItemInfo; if (taskBar != null) { taskBar.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None; @@ -764,7 +772,7 @@ namespace ICSharpCode.ILSpy.TextView { if (state != null) { - state.RestoreFoldings(textOutput.Foldings, SettingsService.Instance.DisplaySettings.ExpandMemberDefinitions); + state.RestoreFoldings(textOutput.Foldings, settingsService.DisplaySettings.ExpandMemberDefinitions); textEditor.ScrollToVerticalOffset(state.VerticalOffset); textEditor.ScrollToHorizontalOffset(state.HorizontalOffset); } @@ -788,7 +796,7 @@ namespace ICSharpCode.ILSpy.TextView } currentAddress = textOutput.Address; currentTitle = textOutput.Title; - expandMemberDefinitions = SettingsService.Instance.DisplaySettings.ExpandMemberDefinitions; + expandMemberDefinitions = settingsService.DisplaySettings.ExpandMemberDefinitions; } #endregion diff --git a/ILSpy/TextView/DocumentationUIBuilder.cs b/ILSpy/TextView/DocumentationUIBuilder.cs index 4d0c5eb78..56b53b98f 100644 --- a/ILSpy/TextView/DocumentationUIBuilder.cs +++ b/ILSpy/TextView/DocumentationUIBuilder.cs @@ -19,15 +19,12 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.IO; using System.Linq; using System.Text; -using System.Text.RegularExpressions; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media; -using System.Xml; using System.Xml.Linq; using ICSharpCode.AvalonEdit.Document; @@ -47,14 +44,16 @@ namespace ICSharpCode.ILSpy.TextView { readonly IAmbience ambience; readonly IHighlightingDefinition highlightingDefinition; + readonly DisplaySettings displaySettings; readonly FlowDocument document; BlockCollection blockCollection; InlineCollection inlineCollection; - public DocumentationUIBuilder(IAmbience ambience, IHighlightingDefinition highlightingDefinition) + public DocumentationUIBuilder(IAmbience ambience, IHighlightingDefinition highlightingDefinition, DisplaySettings displaySettings) { this.ambience = ambience; this.highlightingDefinition = highlightingDefinition; + this.displaySettings = displaySettings; this.document = new FlowDocument(); this.blockCollection = document.Blocks; @@ -115,12 +114,12 @@ namespace ICSharpCode.ILSpy.TextView // Paragraph sadly does not support TextWrapping.NoWrap var text = new TextBlock { FontFamily = GetCodeFont(), - FontSize = SettingsService.Instance.DisplaySettings.SelectedFontSize, + FontSize = displaySettings.SelectedFontSize, TextAlignment = TextAlignment.Left }; text.Inlines.AddRange(richText.CreateRuns(document)); 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.FontFamily = GetCodeFont(); block.TextAlignment = TextAlignment.Left; @@ -435,7 +434,7 @@ namespace ICSharpCode.ILSpy.TextView FontFamily GetCodeFont() { - return SettingsService.Instance.DisplaySettings.SelectedFont; + return displaySettings.SelectedFont; } public void AddInline(Inline inline) diff --git a/ILSpy/Themes/WindowStyleManagerBehavior.cs b/ILSpy/Themes/WindowStyleManagerBehavior.cs index 681fbf97e..1db815ffe 100644 --- a/ILSpy/Themes/WindowStyleManagerBehavior.cs +++ b/ILSpy/Themes/WindowStyleManagerBehavior.cs @@ -27,6 +27,7 @@ using ICSharpCode.ILSpy.Options; using TomsToolbox.Essentials; using TomsToolbox.Wpf; +using TomsToolbox.Wpf.Composition; using TomsToolbox.Wpf.Interactivity; namespace ICSharpCode.ILSpy.Themes @@ -42,7 +43,7 @@ namespace ICSharpCode.ILSpy.Themes { base.OnAttached(); - SettingsService.Instance.DisplaySettings.PropertyChanged += DisplaySettings_PropertyChanged; + MessageBus<SettingsChangedEventArgs>.Subscribers += (sender, e) => DisplaySettings_PropertyChanged(sender, e); _foreground = AssociatedObject.Track(Control.ForegroundProperty); _background = AssociatedObject.Track(Control.BackgroundProperty); @@ -50,7 +51,7 @@ namespace ICSharpCode.ILSpy.Themes _foreground.Changed += Color_Changed; _background.Changed += Color_Changed; - UpdateWindowStyle(); + UpdateWindowStyle(AssociatedObject.GetExportProvider().GetExportedValue<SettingsService>().DisplaySettings); ApplyThemeToWindowCaption(); } @@ -60,8 +61,6 @@ namespace ICSharpCode.ILSpy.Themes _foreground.Changed -= Color_Changed; _background.Changed -= Color_Changed; - - SettingsService.Instance.DisplaySettings.PropertyChanged -= DisplaySettings_PropertyChanged; } private void Color_Changed(object sender, EventArgs e) @@ -69,12 +68,14 @@ namespace ICSharpCode.ILSpy.Themes ApplyThemeToWindowCaption(); } - private void UpdateWindowStyle() + private void UpdateWindowStyle(DisplaySettings displaySettings) { var window = AssociatedObject; - if (SettingsService.Instance.DisplaySettings.StyleWindowTitleBar) + if (displaySettings.StyleWindowTitleBar) + { window.Style = (Style)window.FindResource(TomsToolbox.Wpf.Styles.ResourceKeys.WindowStyle); + } } private static void ShowRestartNotification() @@ -84,16 +85,19 @@ namespace ICSharpCode.ILSpy.Themes private void DisplaySettings_PropertyChanged(object sender, PropertyChangedEventArgs e) { - if (e.PropertyName == nameof(DisplaySettings.StyleWindowTitleBar)) - { - if (!SettingsService.Instance.DisplaySettings.StyleWindowTitleBar) - { - restartNotificationThrottle.Tick(); - return; - } + if (sender is not DisplaySettings displaySettings) + return; + + if (e.PropertyName != nameof(DisplaySettings.StyleWindowTitleBar)) + return; - UpdateWindowStyle(); + if (!displaySettings.StyleWindowTitleBar) + { + restartNotificationThrottle.Tick(); + return; } + + UpdateWindowStyle(displaySettings); } private void ApplyThemeToWindowCaption() diff --git a/ILSpy/TreeNodes/AssemblyListTreeNode.cs b/ILSpy/TreeNodes/AssemblyListTreeNode.cs index e8a984087..3f5b5342e 100644 --- a/ILSpy/TreeNodes/AssemblyListTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyListTreeNode.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Windows; @@ -25,6 +26,7 @@ using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.Util; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX.TreeView; using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions; @@ -45,7 +47,10 @@ namespace ICSharpCode.ILSpy.TreeNodes public AssemblyListTreeNode(AssemblyList assemblyList) { - this.assemblyList = assemblyList ?? throw new ArgumentNullException(nameof(assemblyList)); + ArgumentNullException.ThrowIfNull(assemblyList); + + this.assemblyList = assemblyList; + BindToObservableCollection(assemblyList); } @@ -107,8 +112,8 @@ namespace ICSharpCode.ILSpy.TreeNodes .Distinct() .ToArray(); assemblyList.Move(assemblies, index); - var nodes = assemblies.SelectArray(MainWindow.Instance.AssemblyTreeModel.FindTreeNode); - MainWindow.Instance.AssemblyTreeModel.SelectNodes(nodes); + var nodes = assemblies.SelectArray(AssemblyTreeModel.FindTreeNode); + AssemblyTreeModel.SelectNodes(nodes); } } diff --git a/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs b/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs index 57a326353..c62af32d8 100644 --- a/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs @@ -85,11 +85,11 @@ namespace ICSharpCode.ILSpy.TreeNodes { 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); if (referencedModule != null) { - var module = (MetadataModule)referencedModule.GetTypeSystemWithCurrentOptionsOrNull().MainModule; + var module = (MetadataModule)referencedModule.GetTypeSystemWithCurrentOptionsOrNull(SettingsService)?.MainModule; foreach (var childRef in referencedModule.AssemblyReferences) this.Children.Add(new AssemblyReferenceTreeNode(module, childRef, parentAssembly)); } diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs index ac1187d36..7812767c8 100644 --- a/ILSpy/TreeNodes/AssemblyTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs @@ -263,7 +263,7 @@ namespace ICSharpCode.ILSpy.TreeNodes ns.Children.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)) { var ns = GetOrCreateNamespaceTreeNode(type.Namespace); @@ -329,7 +329,7 @@ namespace ICSharpCode.ILSpy.TreeNodes ns.Children.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)) { 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|*.*"; if (dlg.ShowDialog() == true) { - var options = LanguageService.Instance.CreateDecompilationOptions(DockWorkspace.Instance.ActiveTabPage); + var options = DockWorkspace.Instance.ActiveTabPage.CreateDecompilationOptions(); options.FullDecompilation = true; if (dlg.FilterIndex == 1) { @@ -608,7 +608,7 @@ namespace ICSharpCode.ILSpy.TreeNodes [ExportContextMenuEntry(Header = nameof(Resources._Reload), Icon = "images/Refresh")] [Shared] - sealed class ReloadAssembly : IContextMenuEntry + sealed class ReloadAssembly(AssemblyTreeModel assemblyTreeModel) : IContextMenuEntry { public bool IsVisible(TextViewContext context) { @@ -636,14 +636,14 @@ namespace ICSharpCode.ILSpy.TreeNodes la.AssemblyList.ReloadAssembly(la.FileName); } } - MainWindow.Instance.AssemblyTreeModel.SelectNodes(paths.Select(p => MainWindow.Instance.AssemblyTreeModel.FindNodeByPath(p, true)).ToArray()); - MainWindow.Instance.AssemblyTreeModel.RefreshDecompiledView(); + assemblyTreeModel.SelectNodes(paths.Select(p => assemblyTreeModel.FindNodeByPath(p, true)).ToArray()); + assemblyTreeModel.RefreshDecompiledView(); } } [ExportContextMenuEntry(Header = nameof(Resources._LoadDependencies), Category = nameof(Resources.Dependencies))] [Shared] - sealed class LoadDependencies : IContextMenuEntry + sealed class LoadDependencies(AssemblyTreeModel assemblyTreeModel) : IContextMenuEntry { public bool IsVisible(TextViewContext context) { @@ -677,13 +677,13 @@ namespace ICSharpCode.ILSpy.TreeNodes } } await Task.WhenAll(tasks); - MainWindow.Instance.AssemblyTreeModel.RefreshDecompiledView(); + assemblyTreeModel.RefreshDecompiledView(); } } [ExportContextMenuEntry(Header = nameof(Resources._AddMainList), Category = nameof(Resources.Dependencies))] [Shared] - sealed class AddToMainList : IContextMenuEntry + sealed class AddToMainList(AssemblyTreeModel assemblyTreeModel) : IContextMenuEntry { public bool IsVisible(TextViewContext context) { @@ -712,7 +712,8 @@ namespace ICSharpCode.ILSpy.TreeNodes node.RaisePropertyChanged(nameof(ILSpyTreeNode.IsAutoLoaded)); } } - MainWindow.Instance.AssemblyTreeModel.AssemblyList.RefreshSave(); + + assemblyTreeModel.AssemblyList.RefreshSave(); } } diff --git a/ILSpy/TreeNodes/DerivedTypesEntryNode.cs b/ILSpy/TreeNodes/DerivedTypesEntryNode.cs index bf1366fc1..ac068f24c 100644 --- a/ILSpy/TreeNodes/DerivedTypesEntryNode.cs +++ b/ILSpy/TreeNodes/DerivedTypesEntryNode.cs @@ -55,7 +55,7 @@ namespace ICSharpCode.ILSpy.TreeNodes return FilterResult.Hidden; 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; else return FilterResult.Match; diff --git a/ILSpy/TreeNodes/EventTreeNode.cs b/ILSpy/TreeNodes/EventTreeNode.cs index 3770a2424..ad75b1b5b 100644 --- a/ILSpy/TreeNodes/EventTreeNode.cs +++ b/ILSpy/TreeNodes/EventTreeNode.cs @@ -51,8 +51,8 @@ namespace ICSharpCode.ILSpy.TreeNodes private IEvent GetEventDefinition() { - return ((MetadataModule)EventDefinition.ParentModule.MetadataFile - ?.GetTypeSystemWithCurrentOptionsOrNull() + return ((MetadataModule)EventDefinition.ParentModule?.MetadataFile + ?.GetTypeSystemWithCurrentOptionsOrNull(SettingsService) ?.MainModule)?.GetDefinition((EventDefinitionHandle)EventDefinition.MetadataToken) ?? EventDefinition; } @@ -72,7 +72,7 @@ namespace ICSharpCode.ILSpy.TreeNodes { if (settings.ShowApiLevel == ApiVisibility.PublicOnly && !IsPublicAPI) 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; else return FilterResult.Hidden; diff --git a/ILSpy/TreeNodes/FieldTreeNode.cs b/ILSpy/TreeNodes/FieldTreeNode.cs index 913418d7e..26319a03d 100644 --- a/ILSpy/TreeNodes/FieldTreeNode.cs +++ b/ILSpy/TreeNodes/FieldTreeNode.cs @@ -43,8 +43,8 @@ namespace ICSharpCode.ILSpy.TreeNodes private IField GetFieldDefinition() { - return ((MetadataModule)FieldDefinition.ParentModule.MetadataFile - ?.GetTypeSystemWithCurrentOptionsOrNull() + return ((MetadataModule)FieldDefinition.ParentModule?.MetadataFile + ?.GetTypeSystemWithCurrentOptionsOrNull(SettingsService) ?.MainModule)?.GetDefinition((FieldDefinitionHandle)FieldDefinition.MetadataToken) ?? FieldDefinition; } @@ -73,7 +73,7 @@ namespace ICSharpCode.ILSpy.TreeNodes { if (settings.ShowApiLevel == ApiVisibility.PublicOnly && !IsPublicAPI) 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; else return FilterResult.Hidden; diff --git a/ILSpy/TreeNodes/ILSpyTreeNode.cs b/ILSpy/TreeNodes/ILSpyTreeNode.cs index a65b88300..dbaa2d6ed 100644 --- a/ILSpy/TreeNodes/ILSpyTreeNode.cs +++ b/ILSpy/TreeNodes/ILSpyTreeNode.cs @@ -16,7 +16,6 @@ // 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.Collections.Specialized; using System.ComponentModel; @@ -27,6 +26,7 @@ using System.Windows.Threading; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpyX.Abstractions; using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions; using ICSharpCode.ILSpyX.TreeView; @@ -45,9 +45,17 @@ namespace ICSharpCode.ILSpy.TreeNodes 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) { @@ -71,8 +79,11 @@ namespace ICSharpCode.ILSpy.TreeNodes public override void ActivateItemSecondary(IPlatformRoutedEventArgs e) { - MainWindow.Instance.AssemblyTreeModel.SelectNode(this, inNewTabPage: true); - MainWindow.Instance.Dispatcher.BeginInvoke(DispatcherPriority.Background, (Action)MainWindow.Instance.AssemblyTreeModel.RefreshDecompiledView); + var assemblyTreeModel = AssemblyTreeModel; + + assemblyTreeModel.SelectNode(this, inNewTabPage: true); + + App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, assemblyTreeModel.RefreshDecompiledView); } /// <summary> @@ -87,6 +98,8 @@ namespace ICSharpCode.ILSpy.TreeNodes public override void OnChildrenChanged(NotifyCollectionChangedEventArgs e) { + base.OnChildrenChanged(e); + if (e.NewItems != null) { if (IsVisible) @@ -99,7 +112,6 @@ namespace ICSharpCode.ILSpy.TreeNodes childrenNeedFiltering = true; } } - base.OnChildrenChanged(e); } void ApplyFilterToChild(ILSpyTreeNode child) @@ -162,11 +174,11 @@ namespace ICSharpCode.ILSpy.TreeNodes protected string GetSuffixString(EntityHandle handle) { - if (!SettingsService.Instance.DisplaySettings.ShowMetadataTokens) + if (!SettingsService.DisplaySettings.ShowMetadataTokens) return string.Empty; int token = MetadataTokens.GetToken(handle); - if (SettingsService.Instance.DisplaySettings.ShowMetadataTokensInBase10) + if (SettingsService.DisplaySettings.ShowMetadataTokensInBase10) return " @" + token; return " @" + token.ToString("x8"); } diff --git a/ILSpy/TreeNodes/MethodTreeNode.cs b/ILSpy/TreeNodes/MethodTreeNode.cs index e6bef5f10..f3d2a6daa 100644 --- a/ILSpy/TreeNodes/MethodTreeNode.cs +++ b/ILSpy/TreeNodes/MethodTreeNode.cs @@ -43,8 +43,8 @@ namespace ICSharpCode.ILSpy.TreeNodes private IMethod GetMethodDefinition() { - return ((MetadataModule)MethodDefinition.ParentModule.MetadataFile - ?.GetTypeSystemWithCurrentOptionsOrNull() + return ((MetadataModule)MethodDefinition.ParentModule?.MetadataFile + ?.GetTypeSystemWithCurrentOptionsOrNull(SettingsService) ?.MainModule)?.GetDefinition((MethodDefinitionHandle)MethodDefinition.MetadataToken) ?? MethodDefinition; } @@ -103,7 +103,7 @@ namespace ICSharpCode.ILSpy.TreeNodes { if (settings.ShowApiLevel == ApiVisibility.PublicOnly && !IsPublicAPI) 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; else return FilterResult.Hidden; @@ -127,7 +127,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public override string ToString() { - return LanguageService.Instance.ILLanguage.MethodToString(MethodDefinition, false, false, false); + return LanguageService.ILLanguage.MethodToString(MethodDefinition, false, false, false); } } } diff --git a/ILSpy/TreeNodes/PropertyTreeNode.cs b/ILSpy/TreeNodes/PropertyTreeNode.cs index e9539c887..df1a9f473 100644 --- a/ILSpy/TreeNodes/PropertyTreeNode.cs +++ b/ILSpy/TreeNodes/PropertyTreeNode.cs @@ -53,8 +53,8 @@ namespace ICSharpCode.ILSpy.TreeNodes private IProperty GetPropertyDefinition() { - return ((MetadataModule)PropertyDefinition.ParentModule.MetadataFile - ?.GetTypeSystemWithCurrentOptionsOrNull() + return ((MetadataModule)PropertyDefinition.ParentModule?.MetadataFile + ?.GetTypeSystemWithCurrentOptionsOrNull(SettingsService) ?.MainModule)?.GetDefinition((PropertyDefinitionHandle)PropertyDefinition.MetadataToken) ?? PropertyDefinition; } @@ -75,7 +75,7 @@ namespace ICSharpCode.ILSpy.TreeNodes { if (settings.ShowApiLevel == ApiVisibility.PublicOnly && !IsPublicAPI) 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; else return FilterResult.Hidden; @@ -104,7 +104,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public override string ToString() { - return LanguageService.Instance.ILLanguage.PropertyToString(PropertyDefinition, false, false, false); + return LanguageService.ILLanguage.PropertyToString(PropertyDefinition, false, false, false); } } } diff --git a/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs b/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs index 355a96537..c8c4dd8d0 100644 --- a/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs +++ b/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs @@ -49,7 +49,7 @@ namespace ICSharpCode.ILSpy.TreeNodes protected override void LoadChildren() { 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)) this.Children.Add(new AssemblyReferenceTreeNode(metadataModule, r, parentAssembly)); foreach (var r in metadata.GetModuleReferences().OrderBy(r => metadata.GetString(metadata.GetModuleReference(r).Name))) diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs index 5786c88c8..92e319802 100644 --- a/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs @@ -22,7 +22,6 @@ using System.IO; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.CSharp.ProjectDecompiler; using ICSharpCode.Decompiler.Metadata; -using ICSharpCode.ILSpyX.Abstractions; using Microsoft.Win32; @@ -58,7 +57,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public static ILSpyTreeNode Create(Resource resource) { ILSpyTreeNode result = null; - foreach (var factory in App.ExportProvider.GetExportedValues<IResourceNodeFactory>()) + foreach (var factory in ResourceNodeFactories) { result = factory.CreateNode(resource) as ILSpyTreeNode; if (result != null) diff --git a/ILSpy/TreeNodes/TypeTreeNode.cs b/ILSpy/TreeNodes/TypeTreeNode.cs index 620fe9bf2..a79b5c654 100644 --- a/ILSpy/TreeNodes/TypeTreeNode.cs +++ b/ILSpy/TreeNodes/TypeTreeNode.cs @@ -49,8 +49,8 @@ namespace ICSharpCode.ILSpy.TreeNodes { return ((MetadataModule)ParentAssemblyNode.LoadedAssembly .GetMetadataFileOrNull() - ?.GetTypeSystemWithCurrentOptionsOrNull() - ?.MainModule).GetDefinition((SRM.TypeDefinitionHandle)TypeDefinition.MetadataToken); + ?.GetTypeSystemWithCurrentOptionsOrNull(SettingsService) + ?.MainModule)?.GetDefinition((SRM.TypeDefinitionHandle)TypeDefinition.MetadataToken); } public override bool IsPublicAPI { @@ -73,7 +73,7 @@ namespace ICSharpCode.ILSpy.TreeNodes return FilterResult.Hidden; 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; else return FilterResult.Hidden; diff --git a/ILSpy/Util/MenuService.cs b/ILSpy/Util/MenuService.cs index 6b1d2e29d..340dd7fb9 100644 --- a/ILSpy/Util/MenuService.cs +++ b/ILSpy/Util/MenuService.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System.Collections.Generic; +using System.Composition; using System.Globalization; using System.Linq; using System.Windows; @@ -35,10 +36,10 @@ using TomsToolbox.Wpf.Converters; 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; public void Init(Menu mainMenu, ToolBar toolBar, InputBindingCollection inputBindings) @@ -48,9 +49,9 @@ namespace ICSharpCode.ILSpy.Util 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 var parentMenuItems = new Dictionary<string, MenuItem>(); 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; } - static void InitToolbar(ToolBar toolBar) + void InitToolbar(ToolBar toolBar) { int navigationPos = 0; int openPos = 1; - var toolbarCommandsByTitle = App.ExportProvider.GetExports<ICommand, IToolbarCommandMetadata>("ToolbarCommand") + var toolbarCommandsByTitle = exportProvider.GetExports<ICommand, IToolbarCommandMetadata>("ToolbarCommand") .OrderBy(c => c.Metadata?.ToolbarOrder) .GroupBy(c => c.Metadata?.ToolbarCategory); diff --git a/ILSpy/Util/SettingsService.cs b/ILSpy/Util/SettingsService.cs index 46a132e75..6ce11ee33 100644 --- a/ILSpy/Util/SettingsService.cs +++ b/ILSpy/Util/SettingsService.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Concurrent; using System.ComponentModel; +using System.Composition; using System.Xml.Linq; 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(); - - private SettingsService() : base(LoadSettings()) - { - } + public static readonly SettingsService Instance = App.ExportProvider.GetExportedValue<SettingsService>(); public SessionSettings SessionSettings => GetSettings<SessionSettings>(); diff --git a/ILSpy/ViewModels/ManageAssemblyListsViewModel.cs b/ILSpy/ViewModels/ManageAssemblyListsViewModel.cs index 76ab7aedb..9d73655d3 100644 --- a/ILSpy/ViewModels/ManageAssemblyListsViewModel.cs +++ b/ILSpy/ViewModels/ManageAssemblyListsViewModel.cs @@ -35,11 +35,13 @@ namespace ICSharpCode.ILSpy.ViewModels { private readonly AssemblyListManager manager; 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.sessionSettings = settingsService.SessionSettings; NewCommand = new DelegateCommand(ExecuteNew); CloneCommand = new DelegateCommand(ExecuteClone, CanExecuteClone); @@ -174,7 +176,7 @@ namespace ICSharpCode.ILSpy.ViewModels return; manager.ClearAll(); manager.CreateDefaultAssemblyLists(); - SettingsService.Instance.SessionSettings.ActiveAssemblyList = manager.AssemblyLists[0]; + sessionSettings.ActiveAssemblyList = manager.AssemblyLists[0]; } private void ExecuteDelete() @@ -189,9 +191,9 @@ namespace ICSharpCode.ILSpy.ViewModels if (manager.AssemblyLists.Count > 0) { 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; SelectedAssemblyList = 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() { - SettingsService.Instance.SessionSettings.ActiveAssemblyList = SelectedAssemblyList; + sessionSettings.ActiveAssemblyList = SelectedAssemblyList; this.parent.Close(); } } diff --git a/ILSpy/ViewModels/TabPageModel.cs b/ILSpy/ViewModels/TabPageModel.cs index 20e4bfb67..9d7366b41 100644 --- a/ILSpy/ViewModels/TabPageModel.cs +++ b/ILSpy/ViewModels/TabPageModel.cs @@ -21,6 +21,8 @@ using System.Linq; using System.Threading.Tasks; using System.Windows; +using ICSharpCode.Decompiler; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.TextView; using TomsToolbox.Wpf; @@ -29,8 +31,16 @@ namespace ICSharpCode.ILSpy.ViewModels { 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; } @@ -72,7 +82,7 @@ namespace ICSharpCode.ILSpy.ViewModels { if (!(tabPage.Content is DecompilerTextView textView)) { - textView = new DecompilerTextView(); + textView = new DecompilerTextView(tabPage); tabPage.Content = textView; } tabPage.Title = Properties.Resources.Decompiling; @@ -83,7 +93,7 @@ namespace ICSharpCode.ILSpy.ViewModels { if (!(tabPage.Content is DecompilerTextView textView)) { - textView = new DecompilerTextView(); + textView = new DecompilerTextView(tabPage); tabPage.Content = textView; } string oldTitle = tabPage.Title; @@ -105,7 +115,7 @@ namespace ICSharpCode.ILSpy.ViewModels { if (!(tabPage.Content is DecompilerTextView textView)) { - textView = new DecompilerTextView(); + textView = new DecompilerTextView(tabPage); tabPage.Content = textView; } string oldTitle = tabPage.Title; @@ -129,6 +139,11 @@ namespace ICSharpCode.ILSpy.ViewModels 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 diff --git a/ILSpy/Views/DebugSteps.xaml.cs b/ILSpy/Views/DebugSteps.xaml.cs index 7957802e5..9442eff70 100644 --- a/ILSpy/Views/DebugSteps.xaml.cs +++ b/ILSpy/Views/DebugSteps.xaml.cs @@ -7,6 +7,7 @@ using System.Windows.Input; using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.IL.Transforms; +using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.ViewModels; @@ -18,6 +19,10 @@ namespace ICSharpCode.ILSpy [NonShared] public partial class DebugSteps : UserControl { + private readonly AssemblyTreeModel assemblyTreeModel; + private readonly SettingsService settingsService; + private readonly LanguageService languageService; + static readonly ILAstWritingOptions writingOptions = new ILAstWritingOptions { UseFieldSugar = true, UseLogicOperationSugar = true @@ -28,8 +33,12 @@ namespace ICSharpCode.ILSpy #if DEBUG ILAstLanguage language; #endif - public DebugSteps() + public DebugSteps(AssemblyTreeModel assemblyTreeModel, SettingsService settingsService, LanguageService languageService) { + this.assemblyTreeModel = assemblyTreeModel; + this.settingsService = settingsService; + this.languageService = languageService; + InitializeComponent(); #if DEBUG @@ -38,7 +47,7 @@ namespace ICSharpCode.ILSpy writingOptions.PropertyChanged += WritingOptions_PropertyChanged; - if (LanguageService.Instance.Language is ILAstLanguage l) + if (languageService.Language is ILAstLanguage l) { l.StepperUpdated += ILAstStepperUpdated; language = l; @@ -72,7 +81,7 @@ namespace ICSharpCode.ILSpy { language.StepperUpdated -= ILAstStepperUpdated; } - if (LanguageService.Instance.Language is ILAstLanguage l) + if (languageService.Language is ILAstLanguage l) { l.StepperUpdated += ILAstStepperUpdated; language = l; @@ -123,10 +132,9 @@ namespace ICSharpCode.ILSpy void DecompileAsync(int step, bool isDebug = false) { lastSelectedStep = step; - var window = MainWindow.Instance; var state = DockWorkspace.Instance.ActiveTabPage.GetState(); - DockWorkspace.Instance.ActiveTabPage.ShowTextViewAsync(textView => textView.DecompileAsync(window.AssemblyTreeModel.CurrentLanguage, window.AssemblyTreeModel.SelectedNodes, - new DecompilationOptions(window.AssemblyTreeModel.CurrentLanguageVersion, SettingsService.Instance.DecompilerSettings, SettingsService.Instance.DisplaySettings) { + DockWorkspace.Instance.ActiveTabPage.ShowTextViewAsync(textView => textView.DecompileAsync(assemblyTreeModel.CurrentLanguage, assemblyTreeModel.SelectedNodes, + new DecompilationOptions(assemblyTreeModel.CurrentLanguageVersion, settingsService.DecompilerSettings, settingsService.DisplaySettings) { StepLimit = step, IsDebug = isDebug, TextViewState = state as TextView.DecompilerTextViewState diff --git a/ILSpy/Views/ManageAssemblyLIstsDialog.xaml.cs b/ILSpy/Views/ManageAssemblyLIstsDialog.xaml.cs index 111c3c7c7..93efc3e98 100644 --- a/ILSpy/Views/ManageAssemblyLIstsDialog.xaml.cs +++ b/ILSpy/Views/ManageAssemblyLIstsDialog.xaml.cs @@ -29,10 +29,10 @@ namespace ICSharpCode.ILSpy /// </summary> public partial class ManageAssemblyListsDialog : Window { - public ManageAssemblyListsDialog() + public ManageAssemblyListsDialog(SettingsService settingsService) { InitializeComponent(); - DataContext = new ManageAssemblyListsViewModel(this); + DataContext = new ManageAssemblyListsViewModel(this, settingsService); } private void PreconfiguredAssemblyListsMenuClick(object sender, RoutedEventArgs e) diff --git a/TestPlugin/MainMenuCommand.cs b/TestPlugin/MainMenuCommand.cs index cddde39fd..cd5c60c98 100644 --- a/TestPlugin/MainMenuCommand.cs +++ b/TestPlugin/MainMenuCommand.cs @@ -4,6 +4,7 @@ using System.Composition; using ICSharpCode.ILSpy; +using ICSharpCode.ILSpy.AssemblyTree; namespace TestPlugin { @@ -19,11 +20,11 @@ namespace TestPlugin // 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)] [Shared] - public class UnloadAllAssembliesCommand : SimpleCommand + public class UnloadAllAssembliesCommand(AssemblyTreeModel assemblyTreeModel) : SimpleCommand { 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); }