diff --git a/ICSharpCode.ILSpyX/Analyzers/AnalyzerScope.cs b/ICSharpCode.ILSpyX/Analyzers/AnalyzerScope.cs index 290e225bfa..3a0db60df8 100644 --- a/ICSharpCode.ILSpyX/Analyzers/AnalyzerScope.cs +++ b/ICSharpCode.ILSpyX/Analyzers/AnalyzerScope.cs @@ -40,17 +40,14 @@ public class AnalyzerScope /// public bool IsLocal { get; } - public AssemblyList AssemblyList { get; } - public ISymbol AnalyzedSymbol { get; } public ITypeDefinition TypeScope => typeScope; - Accessibility effectiveAccessibility; + readonly Accessibility effectiveAccessibility; public AnalyzerScope(AssemblyList assemblyList, IEntity entity) { - AssemblyList = assemblyList; assemblyListSnapshot = assemblyList.GetSnapshot(); AnalyzedSymbol = entity; DetermineEffectiveAccessibility(entity, out typeScope, out effectiveAccessibility); diff --git a/ICSharpCode.ILSpyX/Analyzers/IAnalyzer.cs b/ICSharpCode.ILSpyX/Analyzers/IAnalyzer.cs index d21a871837..e028e4b7fd 100644 --- a/ICSharpCode.ILSpyX/Analyzers/IAnalyzer.cs +++ b/ICSharpCode.ILSpyX/Analyzers/IAnalyzer.cs @@ -42,6 +42,7 @@ public interface IAnalyzer public interface IAnalyzerMetadata { string Header { get; } + int Order { get; } } } diff --git a/ILSpy.ReadyToRun/ReadyToRunDisassembler.cs b/ILSpy.ReadyToRun/ReadyToRunDisassembler.cs index ce9e62a1e3..8d08b413eb 100644 --- a/ILSpy.ReadyToRun/ReadyToRunDisassembler.cs +++ b/ILSpy.ReadyToRun/ReadyToRunDisassembler.cs @@ -38,12 +38,14 @@ internal class ReadyToRunDisassembler 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 @@ public void Disassemble(PEFile currentFile, int bitness, ulong address, bool sho ReadyToRunMethod readyToRunMethod = runtimeFunction.Method; WriteCommentLine(readyToRunMethod.SignatureString); - var options = SettingsService.Instance.GetSettings(); + var options = settingsService.GetSettings(); if (options.IsShowGCInfo) { diff --git a/ILSpy.ReadyToRun/ReadyToRunLanguage.cs b/ILSpy.ReadyToRun/ReadyToRunLanguage.cs index 78e4788616..26a3dc0dfc 100644 --- a/ILSpy.ReadyToRun/ReadyToRunLanguage.cs +++ b/ILSpy.ReadyToRun/ReadyToRunLanguage.cs @@ -38,6 +38,10 @@ using ILCompiler.Reflection.ReadyToRun; +using TomsToolbox.Composition; + +using MetadataReader = System.Reflection.Metadata.MetadataReader; + namespace ICSharpCode.ILSpy.ReadyToRun { #if STRESS @@ -97,7 +101,7 @@ public void WriteReference(IMember member, string text, bool isDefinition = fals [Export(typeof(Language))] [Shared] - internal class ReadyToRunLanguage : Language + internal class ReadyToRunLanguage(SettingsService settingsService, IExportProvider exportProvider) : Language { private static readonly ConditionalWeakTable readyToRunReaders = new ConditionalWeakTable(); @@ -175,7 +179,7 @@ public override void DecompileMethod(IMethod method, ITextOutput output, Decompi .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 @@ public override void DecompileMethod(IMethod method, ITextOutput output, Decompi 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 @@ public override void DecompileMethod(IMethod method, ITextOutput output, Decompi public override RichText GetRichTextTooltip(IEntity entity) { - return LanguageService.Instance.ILLanguage.GetRichTextTooltip(entity); + return exportProvider.GetExportedValue().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 7b6f77c281..1149418e86 100644 --- a/ILSpy.Tests/Analyzers/MemberImplementsInterfaceAnalyzerTests.cs +++ b/ILSpy.Tests/Analyzers/MemberImplementsInterfaceAnalyzerTests.cs @@ -145,7 +145,7 @@ public void VerifyReturnsOnlyInterfaceMembers() 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 79bbbee7dc..033deaa1d1 100644 --- a/ILSpy.Tests/Analyzers/MethodUsesAnalyzerTests.cs +++ b/ILSpy.Tests/Analyzers/MethodUsesAnalyzerTests.cs @@ -30,7 +30,7 @@ public void Setup() 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 2a47b84acc..972cb6fc7c 100644 --- a/ILSpy.Tests/Analyzers/TypeUsedByAnalyzerTests.cs +++ b/ILSpy.Tests/Analyzers/TypeUsedByAnalyzerTests.cs @@ -41,7 +41,7 @@ public void Setup() 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 5683b253de..4d7b666397 100644 --- a/ILSpy/AboutPage.cs +++ b/ILSpy/AboutPage.cs @@ -17,14 +17,15 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections.Generic; using System.Composition; using System.IO; using System.Text.RegularExpressions; using System.Windows; using System.Windows.Controls; +using System.Windows.Controls.Primitives; using System.Windows.Data; using System.Windows.Input; -using System.Windows.Navigation; using ICSharpCode.AvalonEdit.Rendering; using ICSharpCode.Decompiler; @@ -32,23 +33,35 @@ using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.Themes; using ICSharpCode.ILSpy.Updates; -using ICSharpCode.ILSpyX.Settings; +using ICSharpCode.ILSpy.ViewModels; namespace ICSharpCode.ILSpy { [ExportMainMenuCommand(ParentMenuID = nameof(Resources._Help), Header = nameof(Resources._About), MenuOrder = 99999)] [Shared] - sealed class AboutPage : SimpleCommand + public sealed class AboutPage : SimpleCommand { + readonly SettingsService settingsService; + readonly IEnumerable aboutPageAdditions; + + public AboutPage(SettingsService settingsService, IEnumerable aboutPageAdditions) + { + this.settingsService = settingsService; + this.aboutPageAdditions = aboutPageAdditions; + MessageBus.Subscribers += (_, e) => ShowAboutPage(e.TabPage); + } + public override void Execute(object parameter) { - MainWindow.Instance.AssemblyTreeModel.NavigateTo( - new RequestNavigateEventArgs(new Uri("resource://aboutpage"), null), - inNewTabPage: true - ); + MessageBus.Send(this, new NavigateToEventArgs(new(new("resource://aboutpage"), null), inNewTabPage: true)); + } + + private void ShowAboutPage(TabPageModel tabPage) + { + tabPage.ShowTextView(Display); } - public static void Display(DecompilerTextView textView) + private void Display(DecompilerTextView textView) { AvalonEditTextOutput output = new AvalonEditTextOutput() { Title = Resources.About, @@ -61,23 +74,26 @@ public static void Display(DecompilerTextView textView) output.AddUIElement( delegate { - StackPanel stackPanel = new StackPanel(); - stackPanel.HorizontalAlignment = HorizontalAlignment.Center; - stackPanel.Orientation = Orientation.Horizontal; - if (NotifyOfUpdatesStrategy.LatestAvailableVersion == null) + StackPanel stackPanel = new() { + HorizontalAlignment = HorizontalAlignment.Center, + Orientation = Orientation.Horizontal + }; + if (UpdateService.LatestAvailableVersion == null) { AddUpdateCheckButton(stackPanel, textView); } else { // we already retrieved the latest version sometime earlier - ShowAvailableVersion(NotifyOfUpdatesStrategy.LatestAvailableVersion, stackPanel); + ShowAvailableVersion(UpdateService.LatestAvailableVersion, stackPanel); } - CheckBox checkBox = new CheckBox(); - checkBox.Margin = new Thickness(4); - checkBox.Content = Resources.AutomaticallyCheckUpdatesEveryWeek; - UpdateSettings settings = new UpdateSettings(SettingsService.Instance.SpySettings); - checkBox.SetBinding(CheckBox.IsCheckedProperty, new Binding("AutomaticUpdateCheckEnabled") { Source = settings }); + CheckBox checkBox = new() { + Margin = new Thickness(4), + Content = Resources.AutomaticallyCheckUpdatesEveryWeek + }; + + var settings = settingsService.GetSettings(); + checkBox.SetBinding(ToggleButton.IsCheckedProperty, new Binding("AutomaticUpdateCheckEnabled") { Source = settings }); return new StackPanel { Margin = new Thickness(0, 4, 0, 0), Cursor = Cursors.Arrow, @@ -86,7 +102,7 @@ public static void Display(DecompilerTextView textView) }); output.WriteLine(); - foreach (var plugin in App.ExportProvider.GetExportedValues()) + foreach (var plugin in aboutPageAdditions) plugin.Write(output); output.WriteLine(); output.Address = new Uri("resource://AboutPage"); @@ -94,8 +110,7 @@ public static void Display(DecompilerTextView textView) { using (StreamReader r = new StreamReader(s)) { - string line; - while ((line = r.ReadLine()) != null) + while (r.ReadLine() is { } line) { output.WriteLine(line); } @@ -156,7 +171,7 @@ static void AddUpdateCheckButton(StackPanel stackPanel, DecompilerTextView textV try { - AvailableVersionInfo vInfo = await NotifyOfUpdatesStrategy.GetLatestVersionAsync(); + AvailableVersionInfo vInfo = await UpdateService.GetLatestVersionAsync(); stackPanel.Children.Clear(); ShowAvailableVersion(vInfo, stackPanel); } @@ -199,7 +214,7 @@ static void ShowAvailableVersion(AvailableVersionInfo availableVersion, StackPan button.Content = Resources.Download; button.Cursor = Cursors.Arrow; button.Click += delegate { - MainWindow.OpenLink(availableVersion.DownloadUrl); + GlobalUtils.OpenLink(availableVersion.DownloadUrl); }; stackPanel.Children.Add(button); } diff --git a/ILSpy/Analyzers/AnalyzeCommand.cs b/ILSpy/Analyzers/AnalyzeCommand.cs index e29dacb23e..20d80d48f2 100644 --- a/ILSpy/Analyzers/AnalyzeCommand.cs +++ b/ILSpy/Analyzers/AnalyzeCommand.cs @@ -20,17 +20,18 @@ 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(); - public bool IsVisible(TextViewContext context) { if (context.TreeView is AnalyzerTreeView && context.SelectedTreeNodes != null && context.SelectedTreeNodes.All(n => n.Parent.IsRoot)) @@ -62,30 +63,30 @@ public void Execute(TextViewContext context) { foreach (var node in context.SelectedTreeNodes.OfType().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 + [Export] + [Shared] + public sealed class AnalyzeCommand(AssemblyTreeModel assemblyTreeModel, AnalyzerTreeViewModel analyzerTreeViewModel) : SimpleCommand { - private static readonly AnalyzerTreeViewModel AnalyzerTreeView = App.ExportProvider.GetExportedValue(); - 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()) + foreach (var node in assemblyTreeModel.SelectedNodes.OfType()) { - AnalyzerTreeView.Analyze(node.Member); + analyzerTreeViewModel.Analyze(node.Member); } } } diff --git a/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs b/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs index 7c3d484bcd..52556d6236 100644 --- a/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs +++ b/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs @@ -58,10 +58,10 @@ protected IEnumerable FetchChildren(CancellationToken ct) { if (symbol is IEntity) { - var context = new AnalyzerContext() { + var context = new AnalyzerContext { CancellationToken = ct, Language = Language, - AssemblyList = MainWindow.Instance.AssemblyTreeModel.AssemblyList + AssemblyList = 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 d2cffeb49f..7937b12b44 100644 --- a/ILSpy/Analyzers/AnalyzerTreeNode.cs +++ b/ILSpy/Analyzers/AnalyzerTreeNode.cs @@ -17,15 +17,22 @@ // 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; + protected static Language Language => App.ExportProvider.GetExportedValue().Language; + + protected static AssemblyList AssemblyList => App.ExportProvider.GetExportedValue(); public override bool CanDelete() { @@ -42,6 +49,11 @@ public override void Delete() DeleteCore(); } + public static ICollection> Analyzers => App.ExportProvider + .GetExports("Analyzer") + .OrderBy(item => item.Metadata?.Order) + .ToArray(); + /// /// Handles changes to the assembly list. /// diff --git a/ILSpy/Analyzers/AnalyzerTreeViewModel.cs b/ILSpy/Analyzers/AnalyzerTreeViewModel.cs index ce45558b92..c325d01516 100644 --- a/ILSpy/Analyzers/AnalyzerTreeViewModel.cs +++ b/ILSpy/Analyzers/AnalyzerTreeViewModel.cs @@ -24,6 +24,7 @@ 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 @@ public class AnalyzerTreeViewModel : ToolPaneModel { 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 8b6ff6f033..f8fccd1125 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 @@ protected override void LoadChildren() 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("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 @@ bool TryFindBackingField(IEvent analyzedEvent, out IField backingField) 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 1f2b9b9a3f..7317841d1b 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 @@ public AnalyzedFieldTreeNode(IField analyzedField) protected override void LoadChildren() { - var analyzers = App.ExportProvider.GetExports("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 b7cee8ede4..283b30a3fb 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 @@ public AnalyzedMethodTreeNode(IMethod analyzedMethod, string prefix = "") protected override void LoadChildren() { - var analyzers = App.ExportProvider.GetExports("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 7f343fb785..a850961476 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 @@ public AnalyzedModuleTreeNode(IModule analyzedModule) protected override void LoadChildren() { - var analyzers = App.ExportProvider.GetExports("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 d19bc3e730..7a4d2fdfaf 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 @@ protected override void LoadChildren() 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("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 6836944eb2..cb3ccc609f 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 @@ public AnalyzedTypeTreeNode(ITypeDefinition analyzedType) protected override void LoadChildren() { - var analyzers = App.ExportProvider.GetExports("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 0ae19f9e17..c82af3125e 100644 --- a/ILSpy/App.xaml.cs +++ b/ILSpy/App.xaml.cs @@ -25,8 +25,6 @@ using System.Runtime.Loader; using System.Threading.Tasks; using System.Windows; -using System.Windows.Documents; -using System.Windows.Navigation; using System.Windows.Threading; using ICSharpCode.ILSpy.AppEnv; @@ -71,8 +69,10 @@ public App() 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,10 +81,10 @@ public App() 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!"); + Exit += (_, _) => MessageBox.Show(StartupExceptions.FormatExceptions(), "Sorry we crashed!", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK, MessageBoxOptions.DefaultDesktopOnly); Shutdown(1); return; } @@ -106,16 +106,13 @@ public App() // 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)) { Thread.CurrentThread.CurrentUICulture = CultureInfo.DefaultThreadCurrentUICulture = new(sessionSettings.CurrentCulture); } - EventManager.RegisterClassHandler(typeof(Window), - Hyperlink.RequestNavigateEvent, - new RequestNavigateEventHandler(Window_RequestNavigate)); ILSpyTraceListener.Install(); if (CommandLineArguments.ArgumentsParser.IsShowingInformation) @@ -129,14 +126,14 @@ public App() MessageBox.Show(unknownArguments, "ILSpy Unknown Command Line Arguments Passed"); } - SettingsService.Instance.AssemblyListManager.CreateDefaultAssemblyLists(); + settingsService.AssemblyListManager.CreateDefaultAssemblyLists(); } public new static App Current => (App)Application.Current; public new MainWindow MainWindow { get => (MainWindow)base.MainWindow; - set => base.MainWindow = value; + private set => base.MainWindow = value; } private static void SingleInstance_NewInstanceDetected(object sender, NewInstanceEventArgs e) => ExportProvider.GetExportedValue().HandleSingleInstanceCommandLineArguments(e.Args).HandleExceptions(); @@ -150,7 +147,7 @@ static Assembly ResolvePluginDependencies(AssemblyLoadContext context, AssemblyN return context.LoadFromAssemblyPath(assemblyFileName); } - private static bool InitializeDependencyInjection(SettingsService settingsService) + private bool InitializeDependencyInjection(SettingsService settingsService) { // Add custom logic for resolution of dependencies. // This necessary because the AssemblyLoadContext.LoadFromAssemblyPath and related methods, @@ -187,11 +184,18 @@ private static bool InitializeDependencyInjection(SettingsService settingsServic 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().DockManager); + services.AddTransient(serviceProvider => serviceProvider.GetService().AssemblyList); var serviceProvider = services.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true }); ExportProvider = new ExportProviderAdapter(serviceProvider); + Exit += (_, _) => serviceProvider.Dispose(); + return true; } catch (Exception ex) @@ -209,7 +213,7 @@ protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); - MainWindow = new(); + MainWindow = ExportProvider.GetExportedValue(); MainWindow.Show(); } @@ -268,10 +272,5 @@ internal static void UnhandledException(Exception exception) } } #endregion - - void Window_RequestNavigate(object sender, RequestNavigateEventArgs e) - { - ExportProvider.GetExportedValue().NavigateTo(e); - } } } \ No newline at end of file diff --git a/ILSpy/AssemblyTree/AssemblyTreeModel.cs b/ILSpy/AssemblyTree/AssemblyTreeModel.cs index 954310192a..3155b29b07 100644 --- a/ILSpy/AssemblyTree/AssemblyTreeModel.cs +++ b/ILSpy/AssemblyTree/AssemblyTreeModel.cs @@ -28,6 +28,7 @@ using System.Reflection.Metadata.Ecma335; using System.Threading.Tasks; using System.Windows; +using System.Windows.Documents; using System.Windows.Input; using System.Windows.Navigation; using System.Windows.Threading; @@ -37,16 +38,15 @@ using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.ILSpy.AppEnv; -using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Properties; -using ICSharpCode.ILSpy.Search; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; +using ICSharpCode.ILSpy.Updates; using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpyX; -using ICSharpCode.ILSpyX.Settings; using ICSharpCode.ILSpyX.TreeView; +using TomsToolbox.Composition; using TomsToolbox.Essentials; using TomsToolbox.Wpf; @@ -56,7 +56,6 @@ namespace ICSharpCode.ILSpy.AssemblyTree { [ExportToolPane] [Shared] - [Export] public class AssemblyTreeModel : ToolPaneModel { public const string PaneContentId = "assemblyListPane"; @@ -67,9 +66,16 @@ public class AssemblyTreeModel : ToolPaneModel private readonly NavigationHistory history = new(); private bool isNavigatingHistory; + private readonly SettingsService settingsService; + private readonly LanguageService languageService; + private readonly IExportProvider exportProvider; - public AssemblyTreeModel() + public AssemblyTreeModel(SettingsService settingsService, LanguageService languageService, IExportProvider exportProvider) { + this.settingsService = settingsService; + this.languageService = languageService; + this.exportProvider = exportProvider; + Title = Resources.Assemblies; ContentId = PaneContentId; IsCloseable = false; @@ -77,10 +83,20 @@ public AssemblyTreeModel() MessageBus.Subscribers += JumpToReference; MessageBus.Subscribers += (sender, e) => Settings_PropertyChanged(sender, e); + MessageBus.Subscribers += ApplySessionSettings; + MessageBus.Subscribers += ActiveTabPageChanged; + MessageBus.Subscribers += ResetLayout; + MessageBus.Subscribers += (_, e) => NavigateTo(e.Request, e.InNewTabPage); + MessageBus.Subscribers += (_, _) => { + Initialize(); + Show(); + }; - refreshThrottle = new DispatcherThrottle(DispatcherPriority.Background, RefreshInternal); + EventManager.RegisterClassHandler(typeof(Window), Hyperlink.RequestNavigateEvent, new RequestNavigateEventHandler((_, e) => NavigateTo(e))); - AssemblyList = SettingsService.Instance.CreateEmptyAssemblyList(); + refreshThrottle = new(DispatcherPriority.Background, RefreshInternal); + + AssemblyList = settingsService.CreateEmptyAssemblyList(); } private void Settings_PropertyChanged(object? sender, PropertyChangedEventArgs e) @@ -151,29 +167,26 @@ private bool HandleCommandLineArguments(CommandLineArguments args) { 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; } /// /// Called on startup or when passed arguments via WndProc from a second instance. - /// In the format case, spySettings is non-null; in the latter it is null. + /// In the format case, updateSettings is non-null; in the latter it is null. /// - private async Task HandleCommandLineArgumentsAfterShowList(CommandLineArguments args, ISettingsProvider? spySettings = null) + private async Task HandleCommandLineArgumentsAfterShowList(CommandLineArguments args, UpdateSettings? updateSettings = 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 - await NavigateOnLaunch(args.NavigateTo, sessionSettings.ActiveTreeViewPath, spySettings, relevantAssemblies); + await NavigateOnLaunch(args.NavigateTo, sessionSettings.ActiveTreeViewPath, updateSettings, relevantAssemblies); if (args.Search != null) { - var searchPane = App.ExportProvider.GetExportedValue(); - - searchPane.SearchTerm = args.Search; - searchPane.Show(); + MessageBus.Send(this, new ShowSearchPageEventArgs(args.Search)); } } @@ -197,7 +210,7 @@ await Dispatcher.InvokeAsync(async () => { }); } - private async Task NavigateOnLaunch(string? navigateTo, string[]? activeTreeViewPath, ISettingsProvider? spySettings, List relevantAssemblies) + private async Task NavigateOnLaunch(string? navigateTo, string[]? activeTreeViewPath, UpdateSettings? updateSettings, List relevantAssemblies) { var initialSelection = SelectedItem; if (navigateTo != null) @@ -254,7 +267,7 @@ private async Task NavigateOnLaunch(string? navigateTo, string[]? activeTreeView { AvalonEditTextOutput output = new AvalonEditTextOutput(); output.Write($"Cannot find '{navigateTo}' in command line specified assemblies."); - DockWorkspace.Instance.ShowText(output); + DockWorkspace.ShowText(output); } } else if (relevantAssemblies.Count == 1) @@ -267,7 +280,7 @@ private async Task NavigateOnLaunch(string? navigateTo, string[]? activeTreeView SelectNode(asmNode); } } - else if (spySettings != null) + else if (updateSettings != null) { SharpTreeNode? node = null; if (activeTreeViewPath?.Length > 0) @@ -290,11 +303,11 @@ private async Task NavigateOnLaunch(string? navigateTo, string[]? activeTreeView SelectNode(node); // only if not showing the about page, perform the update check: - await MainWindow.Instance.ShowMessageIfUpdatesAvailableAsync(spySettings); + MessageBus.Send(this, new CheckIfUpdateAvailableEventArgs()); } else { - DockWorkspace.Instance.ActiveTabPage.ShowTextView(AboutPage.Display); + MessageBus.Send(this, new ShowAboutPageEventArgs(DockWorkspace.ActiveTabPage)); } } } @@ -363,11 +376,11 @@ private static bool CanResolveTypeInPEFile(MetadataFile module, ITypeReference t 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 +390,7 @@ public void Initialize() ShowAssemblyList(AssemblyList); - var sessionSettings = SettingsService.Instance.SessionSettings; + var sessionSettings = settingsService.SessionSettings; if (sessionSettings.ActiveAutoLoadedAssembly != null && File.Exists(sessionSettings.ActiveAutoLoadedAssembly)) { @@ -389,14 +402,14 @@ public void Initialize() private async Task OpenAssemblies() { - await HandleCommandLineArgumentsAfterShowList(App.CommandLineArguments, SettingsService.Instance.SpySettings); + await HandleCommandLineArgumentsAfterShowList(App.CommandLineArguments, settingsService.GetSettings()); if (FormatExceptions(App.StartupExceptions.ToArray(), out var output)) { output.Title = "Startup errors"; - DockWorkspace.Instance.AddTabPage(); - DockWorkspace.Instance.ShowText(output); + DockWorkspace.AddTabPage(); + DockWorkspace.ShowText(output); } } @@ -416,7 +429,7 @@ private static bool FormatExceptions(App.ExceptionData[] exceptions, [NotNullWhe 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) { @@ -431,7 +444,6 @@ private void ShowAssemblyList(AssemblyList assemblyList) AssemblyList.CollectionChanged -= assemblyList_CollectionChanged; AssemblyList = assemblyList; - assemblyList.CollectionChanged += assemblyList_CollectionChanged; assemblyListTreeNode = new(assemblyList) { @@ -514,7 +526,7 @@ public void SelectNode(SharpTreeNode? node, bool inNewTabPage = false) if (inNewTabPage) { - DockWorkspace.Instance.AddTabPage(); + DockWorkspace.AddTabPage(); SelectedItem = null; } @@ -644,7 +656,7 @@ private Task JumpToReferenceAsync(object? reference, bool inNewTabPage = false) switch (reference) { case Decompiler.Disassembler.OpCodeInfo opCode: - MainWindow.OpenLink(opCode.Link); + GlobalUtils.OpenLink(opCode.Link); break; case EntityReference unresolvedEntity: string protocol = unresolvedEntity.Protocol; @@ -655,8 +667,7 @@ private Task JumpToReferenceAsync(object? reference, bool inNewTabPage = false) } if (protocol != "decompile") { - var protocolHandlers = App.ExportProvider.GetExportedValues(); - foreach (var handler in protocolHandlers) + foreach (var handler in exportProvider.GetExportedValues()) { var node = handler.Resolve(protocol, file, unresolvedEntity.Handle, out bool newTabPage); if (node != null) @@ -730,7 +741,7 @@ private void TreeView_SelectionChanged() } else { - var activeTabPage = DockWorkspace.Instance.ActiveTabPage; + var activeTabPage = DockWorkspace.ActiveTabPage; if (!isNavigatingHistory) { @@ -778,7 +789,7 @@ void ContextMenuClosed(object? sender, EventArgs e) public void DecompileSelectedNodes(DecompilerTextViewState? newState = null) { - var activeTabPage = DockWorkspace.Instance.ActiveTabPage; + var activeTabPage = DockWorkspace.ActiveTabPage; activeTabPage.SupportsLanguageSwitching = true; @@ -793,25 +804,21 @@ public void DecompileSelectedNodes(DecompilerTextViewState? newState = null) return; } - var options = LanguageService.Instance.CreateDecompilationOptions(activeTabPage); + var options = activeTabPage.CreateDecompilationOptions(); options.TextViewState = newState; activeTabPage.ShowTextViewAsync(textView => textView.DecompileAsync(this.CurrentLanguage, this.SelectedNodes, options)); } public void RefreshDecompiledView() { - DecompileSelectedNodes(DockWorkspace.Instance.ActiveTabPage.GetState() as DecompilerTextViewState); + DecompileSelectedNodes(DockWorkspace.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 SelectedNodes { - get { - return GetTopLevelSelection().OfType(); - } - } + public IEnumerable SelectedNodes => GetTopLevelSelection().OfType(); #endregion @@ -821,7 +828,7 @@ public void NavigateHistory(bool forward) { isNavigatingHistory = true; - TabPageModel tabPage = DockWorkspace.Instance.ActiveTabPage; + TabPageModel tabPage = DockWorkspace.ActiveTabPage; var state = tabPage.GetState(); if (state != null) history.UpdateCurrent(new NavigationState(tabPage, state)); @@ -829,10 +836,10 @@ public void NavigateHistory(bool forward) TabPageModel activeTabPage = newState.TabPage; - if (!DockWorkspace.Instance.TabPages.Contains(activeTabPage)) - DockWorkspace.Instance.AddTabPage(activeTabPage); + if (!DockWorkspace.TabPages.Contains(activeTabPage)) + DockWorkspace.AddTabPage(activeTabPage); else - DockWorkspace.Instance.ActiveTabPage = activeTabPage; + DockWorkspace.ActiveTabPage = activeTabPage; SelectNodes(newState.TreeNodes); } @@ -846,19 +853,19 @@ public void NavigateHistory(bool forward) public bool CanNavigateForward => history.CanNavigateForward; - public void NavigateTo(RequestNavigateEventArgs e, bool inNewTabPage = false) + private void NavigateTo(RequestNavigateEventArgs e, bool inNewTabPage = false) { if (e.Uri.Scheme == "resource") { if (inNewTabPage) { - DockWorkspace.Instance.AddTabPage(); + DockWorkspace.AddTabPage(); } if (e.Uri.Host == "aboutpage") { RecordHistory(); - DockWorkspace.Instance.ActiveTabPage.ShowTextView(AboutPage.Display); + MessageBus.Send(this, new ShowAboutPageEventArgs(DockWorkspace.ActiveTabPage)); e.Handled = true; return; } @@ -882,7 +889,7 @@ public void NavigateTo(RequestNavigateEventArgs e, bool inNewTabPage = false) } } RecordHistory(); - DockWorkspace.Instance.ShowText(output); + DockWorkspace.ShowText(output); e.Handled = true; } @@ -890,7 +897,7 @@ void RecordHistory() { if (isNavigatingHistory) return; - TabPageModel tabPage = DockWorkspace.Instance.ActiveTabPage; + TabPageModel tabPage = DockWorkspace.ActiveTabPage; var currentState = tabPage.GetState(); if (currentState != null) history.UpdateCurrent(new NavigationState(tabPage, currentState)); @@ -912,7 +919,7 @@ private void RefreshInternal() { var path = GetPathForNode(SelectedItem); - ShowAssemblyList(SettingsService.Instance.AssemblyListManager.LoadList(AssemblyList.ListName)); + ShowAssemblyList(settingsService.AssemblyListManager.LoadList(AssemblyList.ListName)); SelectNode(FindNodeByPath(path, true), inNewTabPage: false); RefreshDecompiledView(); @@ -987,5 +994,48 @@ public void OpenFiles(string[] fileNames, bool focusNode = true) LoadAssemblies(fileNames, focusNode: focusNode); } + + private void ApplySessionSettings(object? sender, ApplySessionSettingsEventArgs e) + { + var settings = e.SessionSettings; + + settings.ActiveAssemblyList = AssemblyList.ListName; + settings.ActiveTreeViewPath = SelectedPath; + settings.ActiveAutoLoadedAssembly = GetAutoLoadedAssemblyNode(SelectedItem); + } + + private static string? GetAutoLoadedAssemblyNode(SharpTreeNode? node) + { + var assemblyTreeNode = node? + .AncestorsAndSelf() + .OfType() + .FirstOrDefault(); + + var loadedAssembly = assemblyTreeNode?.LoadedAssembly; + + return loadedAssembly is not { IsLoaded: true, IsAutoLoaded: true } + ? null + : loadedAssembly.FileName; + } + + private void ActiveTabPageChanged(object? sender, ActiveTabPageChangedEventArgs e) + { + if (e.ViewState is not { } state) + return; + + if (state.DecompiledNodes != null) + { + SelectNodes(state.DecompiledNodes); + } + else + { + NavigateTo(new(state.ViewedUri, null)); + } + + } + private void ResetLayout(object? sender, ResetLayoutEventArgs e) + { + RefreshDecompiledView(); + } } } diff --git a/ILSpy/Commands/CheckForUpdatesCommand.cs b/ILSpy/Commands/CheckForUpdatesCommand.cs index 75ab702e73..a9cb1033aa 100644 --- a/ILSpy/Commands/CheckForUpdatesCommand.cs +++ b/ILSpy/Commands/CheckForUpdatesCommand.cs @@ -27,14 +27,9 @@ namespace ICSharpCode.ILSpy [Shared] sealed class CheckForUpdatesCommand : SimpleCommand { - public override bool CanExecute(object parameter) + public override void Execute(object parameter) { - return base.CanExecute(parameter); - } - - public override async void Execute(object parameter) - { - await MainWindow.Instance.ShowMessageIfUpdatesAvailableAsync(SettingsService.Instance.SpySettings, forceCheck: true); + MessageBus.Send(this, new CheckIfUpdateAvailableEventArgs(notify: true)); } } } diff --git a/ILSpy/Commands/DecompileAllCommand.cs b/ILSpy/Commands/DecompileAllCommand.cs index 72aae604c5..7a9bebf182 100644 --- a/ILSpy/Commands/DecompileAllCommand.cs +++ b/ILSpy/Commands/DecompileAllCommand.cs @@ -27,24 +27,19 @@ 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, DockWorkspace dockWorkspace) : SimpleCommand { - private readonly IReadOnlyCollection resourceFileHandlers; - - public DecompileAllCommand(IEnumerable resourceFileHandlers) - { - this.resourceFileHandlers = resourceFileHandlers.ToArray(); - } - public override bool CanExecute(object parameter) { return System.IO.Directory.Exists("c:\\temp\\decompiled"); @@ -52,10 +47,10 @@ public override bool CanExecute(object parameter) public override void Execute(object parameter) { - Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task.Factory.StartNew(() => { + dockWorkspace.RunWithCancellation(ct => Task.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 @@ public override void Execute(object parameter) { try { - var options = LanguageService.Instance.CreateDecompilationOptions(DockWorkspace.Instance.ActiveTabPage); + var options = dockWorkspace.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) { @@ -90,21 +85,20 @@ public override void Execute(object parameter) } }); return output; - }, ct)).Then(output => Docking.DockWorkspace.Instance.ShowText(output)).HandleExceptions(); + }, ct)).Then(dockWorkspace.ShowText).HandleExceptions(); } } [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, DockWorkspace dockWorkspace) : SimpleCommand { public override void Execute(object parameter) { const int numRuns = 100; - var language = LanguageService.Instance.Language; - var nodes = MainWindow.Instance.AssemblyTreeModel.SelectedNodes.ToArray(); - DockWorkspace dockWorkspace = DockWorkspace.Instance; - var options = LanguageService.Instance.CreateDecompilationOptions(dockWorkspace.ActiveTabPage); + var language = languageService.Language; + var nodes = assemblyTreeModel.SelectedNodes.ToArray(); + var options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions(); dockWorkspace.RunWithCancellation(ct => Task.Factory.StartNew(() => { options.CancellationToken = ct; Stopwatch w = Stopwatch.StartNew(); diff --git a/ILSpy/Commands/DecompileInNewViewCommand.cs b/ILSpy/Commands/DecompileInNewViewCommand.cs index 107a11b46c..3601517b00 100644 --- a/ILSpy/Commands/DecompileInNewViewCommand.cs +++ b/ILSpy/Commands/DecompileInNewViewCommand.cs @@ -35,15 +35,8 @@ namespace ICSharpCode.ILSpy.Commands { [ExportContextMenuEntry(Header = nameof(Resources.DecompileToNewPanel), InputGestureText = "MMB", Icon = "images/Search", Category = nameof(Resources.Analyze), Order = 90)] [Shared] - internal sealed class DecompileInNewViewCommand : IContextMenuEntry + internal sealed class DecompileInNewViewCommand(AssemblyTreeModel assemblyTreeModel, DockWorkspace dockWorkspace) : IContextMenuEntry { - private readonly AssemblyTreeModel assemblyTreeModel; - - public DecompileInNewViewCommand(AssemblyTreeModel assemblyTreeModel) - { - this.assemblyTreeModel = assemblyTreeModel; - } - public bool IsVisible(TextViewContext context) { return context.SelectedTreeNodes != null || context.Reference?.Reference is IEntity; @@ -56,11 +49,11 @@ public bool IsEnabled(TextViewContext context) public void Execute(TextViewContext context) { - var activePane = DockWorkspace.Instance.ActivePane; + var activePane = dockWorkspace.ActivePane; DecompileNodes(GetNodes(context).ToArray()); - DockWorkspace.Instance.ActivePane = activePane; + dockWorkspace.ActivePane = activePane; } IEnumerable GetNodes(TextViewContext context) @@ -98,7 +91,7 @@ void DecompileNodes(ILSpyTreeNode[] nodes) if (nodes.Length == 0) return; - DockWorkspace.Instance.AddTabPage(); + dockWorkspace.AddTabPage(); if (assemblyTreeModel.SelectedItems.SequenceEqual(nodes)) assemblyTreeModel.DecompileSelectedNodes(); diff --git a/ILSpy/Commands/DisassembleAllCommand.cs b/ILSpy/Commands/DisassembleAllCommand.cs index fea58925d9..26682b9d1d 100644 --- a/ILSpy/Commands/DisassembleAllCommand.cs +++ b/ILSpy/Commands/DisassembleAllCommand.cs @@ -24,14 +24,17 @@ using System.Diagnostics; using System.Threading.Tasks; +using ICSharpCode.ILSpy.AssemblyTree; +using ICSharpCode.ILSpy.Docking; 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, DockWorkspace dockWorkspace) : SimpleCommand { public override bool CanExecute(object parameter) { @@ -40,12 +43,10 @@ public override bool CanExecute(object parameter) public override void Execute(object parameter) { - var dockWorkspace = Docking.DockWorkspace.Instance; - dockWorkspace.RunWithCancellation(ct => Task.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,10 +57,10 @@ public override void Execute(object parameter) { 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); + new ILLanguage(dockWorkspace).DecompileAssembly(asm, new Decompiler.PlainTextOutput(writer), options); } catch (Exception ex) { diff --git a/ILSpy/Commands/ExitCommand.cs b/ILSpy/Commands/ExitCommand.cs index 1ba8a34e1d..91483d829b 100644 --- a/ILSpy/Commands/ExitCommand.cs +++ b/ILSpy/Commands/ExitCommand.cs @@ -23,11 +23,11 @@ namespace ICSharpCode.ILSpy { [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.E_xit), MenuOrder = 99999, MenuCategory = nameof(Resources.Exit))] [Shared] - sealed class ExitCommand : SimpleCommand + sealed class ExitCommand(MainWindow mainWindow) : SimpleCommand { public override void Execute(object parameter) { - MainWindow.Instance.Close(); + mainWindow.Close(); } } } \ No newline at end of file diff --git a/ILSpy/Commands/ExtractPackageEntryContextMenuEntry.cs b/ILSpy/Commands/ExtractPackageEntryContextMenuEntry.cs index 2d558aca41..cf715759d3 100644 --- a/ILSpy/Commands/ExtractPackageEntryContextMenuEntry.cs +++ b/ILSpy/Commands/ExtractPackageEntryContextMenuEntry.cs @@ -25,6 +25,7 @@ using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.CSharp.ProjectDecompiler; +using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; @@ -36,7 +37,7 @@ namespace ICSharpCode.ILSpy { [ExportContextMenuEntry(Header = nameof(Resources.ExtractPackageEntry), Category = nameof(Resources.Save), Icon = "Images/Save")] [Shared] - sealed class ExtractPackageEntryContextMenuEntry : IContextMenuEntry + sealed class ExtractPackageEntryContextMenuEntry(DockWorkspace dockWorkspace) : IContextMenuEntry { public void Execute(TextViewContext context) { @@ -61,7 +62,7 @@ public void Execute(TextViewContext context) if (selectedNodes.Length > 1) outputFolderOrFileName = Path.GetDirectoryName(outputFolderOrFileName); - Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task.Factory.StartNew(() => { + dockWorkspace.RunWithCancellation(ct => Task.Factory.StartNew(() => { AvalonEditTextOutput output = new AvalonEditTextOutput(); Stopwatch stopwatch = Stopwatch.StartNew(); stopwatch.Stop(); @@ -83,7 +84,7 @@ public void Execute(TextViewContext context) output.AddButton(null, Resources.OpenExplorer, delegate { Process.Start("explorer", "/select,\"" + fileName + "\""); }); output.WriteLine(); return output; - }, ct)).Then(output => Docking.DockWorkspace.Instance.ShowText(output)).HandleExceptions(); + }, ct)).Then(dockWorkspace.ShowText).HandleExceptions(); } void SaveEntry(ITextOutput output, PackageEntry entry, string targetFileName) diff --git a/ILSpy/Commands/GeneratePdbContextMenuEntry.cs b/ILSpy/Commands/GeneratePdbContextMenuEntry.cs index d31a3160c3..7a03748950 100644 --- a/ILSpy/Commands/GeneratePdbContextMenuEntry.cs +++ b/ILSpy/Commands/GeneratePdbContextMenuEntry.cs @@ -29,10 +29,12 @@ 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, DockWorkspace dockWorkspace) : IContextMenuEntry { public void Execute(TextViewContext context) { var assembly = (context.SelectedTreeNodes?.FirstOrDefault() as AssemblyTreeNode)?.LoadedAssembly; if (assembly == null) return; - GeneratePdbForAssembly(assembly); + GeneratePdbForAssembly(assembly, languageService, dockWorkspace); } public bool IsEnabled(TextViewContext context) => true; @@ -60,7 +62,7 @@ public bool IsVisible(TextViewContext context) && tn.LoadedAssembly.IsLoadedAsValidAssembly; } - internal static void GeneratePdbForAssembly(LoadedAssembly assembly) + internal static void GeneratePdbForAssembly(LoadedAssembly assembly, LanguageService languageService, DockWorkspace dockWorkspace) { var file = assembly.GetMetadataFileOrNull() as PEFile; if (!PortablePdbWriter.HasCodeViewDebugDirectoryEntry(file)) @@ -74,8 +76,7 @@ internal static void GeneratePdbForAssembly(LoadedAssembly assembly) dlg.InitialDirectory = Path.GetDirectoryName(assembly.FileName); 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.Factory.StartNew(() => { AvalonEditTextOutput output = new AvalonEditTextOutput(); @@ -102,27 +103,27 @@ internal static void GeneratePdbForAssembly(LoadedAssembly assembly) output.AddButton(null, Resources.OpenExplorer, delegate { Process.Start("explorer", "/select,\"" + fileName + "\""); }); output.WriteLine(); return output; - }, ct)).Then(output => Docking.DockWorkspace.Instance.ShowText(output)).HandleExceptions(); + }, ct)).Then(dockWorkspace.ShowText).HandleExceptions(); } } [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.GeneratePortable), MenuCategory = nameof(Resources.Save))] [Shared] - class GeneratePdbMainMenuEntry : SimpleCommand + class GeneratePdbMainMenuEntry(AssemblyTreeModel assemblyTreeModel, LanguageService languageService, DockWorkspace dockWorkspace) : 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, dockWorkspace); } } } diff --git a/ILSpy/Commands/ManageAssemblyListsCommand.cs b/ILSpy/Commands/ManageAssemblyListsCommand.cs index 63ab2f0375..02eb5284cc 100644 --- a/ILSpy/Commands/ManageAssemblyListsCommand.cs +++ b/ILSpy/Commands/ManageAssemblyListsCommand.cs @@ -18,6 +18,8 @@ using System.Composition; +using System.Windows; +using System.Windows.Data; using ICSharpCode.ILSpy.Properties; @@ -25,13 +27,21 @@ 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, IProvideParameterBinding { public override void Execute(object parameter) { - ManageAssemblyListsDialog dlg = new ManageAssemblyListsDialog(); - dlg.Owner = MainWindow.Instance; + ManageAssemblyListsDialog dlg = new(settingsService) { + Owner = parameter as Window + }; + dlg.ShowDialog(); } + + public Binding ParameterBinding => new() { + RelativeSource = new(RelativeSourceMode.FindAncestor) { + AncestorType = typeof(Window) + } + }; } } diff --git a/ILSpy/Commands/OpenFromGacCommand.cs b/ILSpy/Commands/OpenFromGacCommand.cs index c7fd898d04..b66e1c644a 100644 --- a/ILSpy/Commands/OpenFromGacCommand.cs +++ b/ILSpy/Commands/OpenFromGacCommand.cs @@ -26,15 +26,8 @@ namespace ICSharpCode.ILSpy { [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.OpenFrom_GAC), MenuIcon = "Images/AssemblyListGAC", MenuCategory = nameof(Resources.Open), MenuOrder = 1)] [Shared] - sealed class OpenFromGacCommand : SimpleCommand + sealed class OpenFromGacCommand(AssemblyTreeModel assemblyTreeModel, MainWindow mainWindow) : SimpleCommand { - private readonly AssemblyTreeModel assemblyTreeModel; - - public OpenFromGacCommand(AssemblyTreeModel assemblyTreeModel) - { - this.assemblyTreeModel = assemblyTreeModel; - } - public override bool CanExecute(object parameter) { return AppEnvironment.IsWindows; @@ -42,8 +35,8 @@ public override bool CanExecute(object parameter) public override void Execute(object parameter) { - OpenFromGacDialog dlg = new OpenFromGacDialog { - Owner = MainWindow.Instance + OpenFromGacDialog dlg = new() { + Owner = mainWindow }; if (dlg.ShowDialog() == true) diff --git a/ILSpy/Commands/Pdb2XmlCommand.cs b/ILSpy/Commands/Pdb2XmlCommand.cs index d4b9a7faeb..13de31ee5f 100644 --- a/ILSpy/Commands/Pdb2XmlCommand.cs +++ b/ILSpy/Commands/Pdb2XmlCommand.cs @@ -26,6 +26,8 @@ using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.Decompiler; +using ICSharpCode.ILSpy.AssemblyTree; +using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; @@ -36,25 +38,25 @@ 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, DockWorkspace dockWorkspace) : 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()); + Execute(assemblyTreeModel.SelectedNodes.OfType(), dockWorkspace); } - internal static void Execute(IEnumerable nodes) + internal static void Execute(IEnumerable nodes, DockWorkspace dockWorkspace) { var highlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml"); var options = PdbToXmlOptions.IncludeEmbeddedSources | PdbToXmlOptions.IncludeMethodSpans | PdbToXmlOptions.IncludeTokens; - Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task.Factory.StartNew(() => { + dockWorkspace.RunWithCancellation(ct => Task.Factory.StartNew(() => { AvalonEditTextOutput output = new AvalonEditTextOutput(); var writer = new TextOutputWriter(output); foreach (var node in nodes) @@ -67,17 +69,17 @@ internal static void Execute(IEnumerable nodes) PdbToXmlConverter.ToXml(writer, pdbStream, peStream, options); } return output; - }, ct)).Then(output => Docking.DockWorkspace.Instance.ShowNodes(output, null, highlighting)).HandleExceptions(); + }, ct)).Then(output => dockWorkspace.ShowNodes(output, null, highlighting)).HandleExceptions(); } } [ExportContextMenuEntry(Header = nameof(Resources.DEBUGDumpPDBAsXML))] [Shared] - class Pdb2XmlCommandContextMenuEntry : IContextMenuEntry + class Pdb2XmlCommandContextMenuEntry(DockWorkspace dockWorkspace) : IContextMenuEntry { public void Execute(TextViewContext context) { - Pdb2XmlCommand.Execute(context.SelectedTreeNodes.OfType()); + Pdb2XmlCommand.Execute(context.SelectedTreeNodes.OfType(), dockWorkspace); } public bool IsEnabled(TextViewContext context) => true; diff --git a/ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs b/ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs index 42673e99a7..da67fd5507 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 @@ public override void Execute(object parameter) { 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 14f9fdf503..071f295990 100644 --- a/ILSpy/Commands/SaveCodeContextMenuEntry.cs +++ b/ILSpy/Commands/SaveCodeContextMenuEntry.cs @@ -23,6 +23,7 @@ using System.Linq; using System.Windows; +using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.ViewModels; @@ -35,11 +36,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, DockWorkspace dockWorkspace) : IContextMenuEntry { public void Execute(TextViewContext context) { - Execute(context.SelectedTreeNodes); + Execute(context.SelectedTreeNodes, languageService, dockWorkspace); } public bool IsEnabled(TextViewContext context) => true; @@ -57,12 +58,9 @@ public static bool CanExecute(IReadOnlyList selectedNodes) || (selectedNodes.Count > 1 && (selectedNodes.All(n => n is AssemblyTreeNode) || selectedNodes.All(n => n is IMemberTreeNode))); } - public static void Execute(IReadOnlyList selectedNodes) + public static void Execute(IReadOnlyList selectedNodes, LanguageService languageService, DockWorkspace dockWorkspace) { - 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) @@ -81,14 +79,14 @@ public static void Execute(IReadOnlyList selectedNodes) var assemblies = selectedNodes.OfType() .Select(n => n.LoadedAssembly) .Where(a => a.IsLoadedAsValidAssembly).ToArray(); - SolutionWriter.CreateSolution(textView, selectedPath, currentLanguage, assemblies); + SolutionWriter.CreateSolution(tabPage, textView, selectedPath, currentLanguage, assemblies); } return; } // 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(), options); }); diff --git a/ILSpy/Commands/SaveCommand.cs b/ILSpy/Commands/SaveCommand.cs index 3b1927e219..ae5ca65057 100644 --- a/ILSpy/Commands/SaveCommand.cs +++ b/ILSpy/Commands/SaveCommand.cs @@ -21,6 +21,7 @@ using System.Windows.Input; using ICSharpCode.ILSpy.AssemblyTree; +using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TextView; @@ -28,16 +29,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, DockWorkspace dockWorkspace) : 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 +39,7 @@ protected override void OnCanExecute(object sender, CanExecuteRoutedEventArgs e) protected override void OnExecute(object sender, ExecutedRoutedEventArgs e) { - SaveCodeContextMenuEntry.Execute(assemblyTreeModel.SelectedNodes.ToList()); + SaveCodeContextMenuEntry.Execute(assemblyTreeModel.SelectedNodes.ToList(), languageService, dockWorkspace); } } } diff --git a/ILSpy/Commands/SearchMsdnContextMenuEntry.cs b/ILSpy/Commands/SearchMsdnContextMenuEntry.cs index 3dfa670320..c6a8babadf 100644 --- a/ILSpy/Commands/SearchMsdnContextMenuEntry.cs +++ b/ILSpy/Commands/SearchMsdnContextMenuEntry.cs @@ -136,7 +136,7 @@ public static void SearchMsdn(ILSpyTreeNode node) address = address.ToLower(); if (!string.IsNullOrEmpty(address)) - MainWindow.OpenLink(address); + GlobalUtils.OpenLink(address); } } } \ No newline at end of file diff --git a/ILSpy/Commands/SelectPdbContextMenuEntry.cs b/ILSpy/Commands/SelectPdbContextMenuEntry.cs index e64ec3881d..9c63a8b8c1 100644 --- a/ILSpy/Commands/SelectPdbContextMenuEntry.cs +++ b/ILSpy/Commands/SelectPdbContextMenuEntry.cs @@ -21,6 +21,7 @@ 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 @@ public async void Execute(TextViewContext context) 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 1f9a1226c9..006faa1071 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/ShowPane.cs b/ILSpy/Commands/ShowPane.cs index 1c6694bd96..5d13f57ced 100644 --- a/ILSpy/Commands/ShowPane.cs +++ b/ILSpy/Commands/ShowPane.cs @@ -3,39 +3,23 @@ namespace ICSharpCode.ILSpy.Commands { - class ToolPaneCommand : SimpleCommand + class ToolPaneCommand(string contentId, DockWorkspace dockWorkspace) : SimpleCommand { - readonly string contentId; - - public ToolPaneCommand(string contentId) - { - this.contentId = contentId; - } - public override void Execute(object parameter) { - DockWorkspace.Instance.ShowToolPane(contentId); + dockWorkspace.ShowToolPane(contentId); } } - class TabPageCommand : SimpleCommand + class TabPageCommand(TabPageModel model, DockWorkspace dockWorkspace) : SimpleCommand { - readonly TabPageModel model; - - public TabPageCommand(TabPageModel model) - { - this.model = model; - } - public override void Execute(object parameter) { - var workspace = DockWorkspace.Instance; - // ensure the tab control is focused before setting the active tab page, else the tab will not be focused - workspace.ActiveTabPage?.Focus(); + dockWorkspace.ActiveTabPage?.Focus(); // reset first, else clicking on the already active tab will not focus the tab and the menu checkmark will not be updated - workspace.ActiveTabPage = null; - workspace.ActiveTabPage = model; + dockWorkspace.ActiveTabPage = null; + dockWorkspace.ActiveTabPage = model; } } } \ No newline at end of file diff --git a/ILSpy/Commands/SimpleCommand.cs b/ILSpy/Commands/SimpleCommand.cs index 67c7f517e1..19c1c7c9ec 100644 --- a/ILSpy/Commands/SimpleCommand.cs +++ b/ILSpy/Commands/SimpleCommand.cs @@ -17,7 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.ComponentModel; +using System.Windows.Data; using System.Windows.Input; namespace ICSharpCode.ILSpy @@ -37,38 +37,8 @@ public virtual bool CanExecute(object parameter) } } - public abstract class ToggleableCommand : ICommand, INotifyPropertyChanged + public interface IProvideParameterBinding { - private bool isChecked; - - public event EventHandler CanExecuteChanged { - add { CommandManager.RequerySuggested += value; } - remove { CommandManager.RequerySuggested -= value; } - } - - public event PropertyChangedEventHandler PropertyChanged; - - void ICommand.Execute(object parameter) - { - IsChecked = Execute(parameter); - } - - public bool IsChecked { - get => isChecked; - set { - if (isChecked != value) - { - isChecked = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsChecked))); - } - } - } - - public abstract bool Execute(object parameter); - - public virtual bool CanExecute(object parameter) - { - return true; - } + Binding ParameterBinding { get; } } } diff --git a/ILSpy/Commands/SortAssemblyListCommand.cs b/ILSpy/Commands/SortAssemblyListCommand.cs index f3a55682dd..a9434f9c21 100644 --- a/ILSpy/Commands/SortAssemblyListCommand.cs +++ b/ILSpy/Commands/SortAssemblyListCommand.cs @@ -20,6 +20,7 @@ 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 5d80ca5f18..1402a09b03 100644 --- a/ILSpy/ContextMenuEntry.cs +++ b/ILSpy/ContextMenuEntry.cs @@ -31,6 +31,7 @@ using TomsToolbox.Composition; using TomsToolbox.Essentials; +using TomsToolbox.Wpf.Composition; namespace ICSharpCode.ILSpy { @@ -222,7 +223,7 @@ public static void Add(DataGrid dataGrid) private ContextMenuProvider(Control control) { - entries = App.ExportProvider.GetExports().ToArray(); + entries = control.GetExportProvider().GetExports().ToArray(); this.control = control; } diff --git a/ILSpy/Controls/ZoomScrollViewer.cs b/ILSpy/Controls/ZoomScrollViewer.cs index 21e258963b..7c14528cb0 100644 --- a/ILSpy/Controls/ZoomScrollViewer.cs +++ b/ILSpy/Controls/ZoomScrollViewer.cs @@ -176,21 +176,4 @@ internal static double RoundToOneIfClose(double val) return val; } } - - sealed class IsNormalZoomConverter : IValueConverter - { - public static readonly IsNormalZoomConverter Instance = new IsNormalZoomConverter(); - - public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) - { - if (parameter is bool && (bool)parameter) - return true; - return ((double)value) == 1.0; - } - - public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) - { - throw new NotImplementedException(); - } - } } diff --git a/ILSpy/Docking/CloseAllDocumentsCommand.cs b/ILSpy/Docking/CloseAllDocumentsCommand.cs index c41f599435..b7f05e50fa 100644 --- a/ILSpy/Docking/CloseAllDocumentsCommand.cs +++ b/ILSpy/Docking/CloseAllDocumentsCommand.cs @@ -6,21 +6,21 @@ namespace ICSharpCode.ILSpy.Docking { [ExportMainMenuCommand(Header = nameof(Resources.Window_CloseAllDocuments), ParentMenuID = nameof(Resources._Window))] [Shared] - class CloseAllDocumentsCommand : SimpleCommand + class CloseAllDocumentsCommand(DockWorkspace dockWorkspace) : SimpleCommand { public override void Execute(object parameter) { - DockWorkspace.Instance.CloseAllTabs(); + dockWorkspace.CloseAllTabs(); } } [ExportMainMenuCommand(Header = nameof(Resources.Window_ResetLayout), ParentMenuID = nameof(Resources._Window))] [Shared] - class ResetLayoutCommand : SimpleCommand + class ResetLayoutCommand(DockWorkspace dockWorkspace) : SimpleCommand { public override void Execute(object parameter) { - DockWorkspace.Instance.ResetLayout(); + dockWorkspace.ResetLayout(); } } } diff --git a/ILSpy/Docking/DockWorkspace.cs b/ILSpy/Docking/DockWorkspace.cs index b196f8e79d..d92b928476 100644 --- a/ILSpy/Docking/DockWorkspace.cs +++ b/ILSpy/Docking/DockWorkspace.cs @@ -20,6 +20,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; +using System.Composition; using System.Linq; using System.Reflection; using System.Threading; @@ -42,41 +43,35 @@ namespace ICSharpCode.ILSpy.Docking { + [Export] + [Shared] public class DockWorkspace : ObservableObject, ILayoutUpdateStrategy { - private static SessionSettings SessionSettings => SettingsService.Instance.SessionSettings; - - private readonly IExportProvider exportProvider = App.ExportProvider; - - public static readonly DockWorkspace Instance = new(); + private readonly IExportProvider exportProvider; private readonly ObservableCollection tabPages = []; - private DockingManager dockingManager; + readonly SessionSettings sessionSettings; - private DockWorkspace() + private DockingManager DockingManager => exportProvider.GetExportedValue(); + + public DockWorkspace(SettingsService settingsService, IExportProvider exportProvider) { - this.tabPages.CollectionChanged += TabPages_CollectionChanged; - TabPages = new(tabPages); + this.exportProvider = exportProvider; - ToolPanes = exportProvider - .GetExportedValues("ToolPane") - .OrderBy(item => item.Title) - .ToArray() - .AsReadOnly(); + sessionSettings = settingsService.SessionSettings; - // Make sure there is at least one tab open - AddTabPage(); + this.tabPages.CollectionChanged += TabPages_CollectionChanged; + TabPages = new(tabPages); MessageBus.Subscribers += (sender, e) => CurrentAssemblyList_Changed(sender, e); } private void CurrentAssemblyList_Changed(object sender, NotifyCollectionChangedEventArgs e) { - if (e.OldItems == null) - { + if (e.OldItems is not { } oldItems) return; - } + foreach (var tab in tabPages.ToArray()) { var state = tab.GetState(); @@ -87,7 +82,7 @@ private void CurrentAssemblyList_Changed(object sender, NotifyCollectionChangedE bool found = decompiledNodes .Select(node => node.Ancestors().OfType().LastOrDefault()) .ExceptNullItems() - .Any(assemblyNode => !e.OldItems.Contains(assemblyNode.LoadedAssembly)); + .Any(assemblyNode => !oldItems.Contains(assemblyNode.LoadedAssembly)); if (!found) { @@ -123,12 +118,16 @@ private void TabPages_CollectionChanged(object sender, NotifyCollectionChangedEv public void AddTabPage(TabPageModel tabPage = null) { - tabPages.Add(tabPage ?? new TabPageModel()); + tabPages.Add(tabPage ?? exportProvider.GetExportedValue()); } public ReadOnlyObservableCollection TabPages { get; } - public ReadOnlyCollection ToolPanes { get; } + public ReadOnlyCollection ToolPanes => exportProvider + .GetExportedValues("ToolPane") + .OrderBy(item => item.Title) + .ToArray() + .AsReadOnly(); public bool ShowToolPane(string contentId) { @@ -161,42 +160,35 @@ public TabPageModel ActiveTabPage { } set { if (!SetProperty(ref activeTabPage, value)) - { return; - } var state = value?.GetState(); - if (state != null) - { - if (state.DecompiledNodes != null) - { - MainWindow.Instance.AssemblyTreeModel.SelectNodes(state.DecompiledNodes); - } - else - { - MainWindow.Instance.AssemblyTreeModel.NavigateTo(new(state.ViewedUri, null)); - } - } + if (state == null) + return; + + MessageBus.Send(this, new ActiveTabPageChangedEventArgs(value?.GetState())); } } public PaneModel ActivePane { - get => dockingManager?.ActiveContent as PaneModel; - set { - if (dockingManager is not null) - dockingManager.ActiveContent = value; - } + get => DockingManager.ActiveContent as PaneModel; + set => DockingManager.ActiveContent = value; } - public void InitializeLayout(DockingManager manager) + public void InitializeLayout() { - this.dockingManager = manager; - manager.LayoutUpdateStrategy = this; - XmlLayoutSerializer serializer = new XmlLayoutSerializer(manager); + if (tabPages.Count == 0) + { + // Make sure there is at least one tab open + AddTabPage(); + } + + DockingManager.LayoutUpdateStrategy = this; + XmlLayoutSerializer serializer = new XmlLayoutSerializer(DockingManager); serializer.LayoutSerializationCallback += LayoutSerializationCallback; try { - SessionSettings.DockLayout.Deserialize(serializer); + sessionSettings.DockLayout.Deserialize(serializer); } finally { @@ -253,9 +245,10 @@ internal void ResetLayout() pane.IsVisible = false; } CloseAllTabs(); - SessionSettings.DockLayout.Reset(); - InitializeLayout(MainWindow.Instance.dockManager); - MainWindow.Instance.Dispatcher.BeginInvoke(DispatcherPriority.Background, (Action)MainWindow.Instance.AssemblyTreeModel.RefreshDecompiledView); + sessionSettings.DockLayout.Reset(); + InitializeLayout(); + + App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, () => MessageBus.Send(this, new ResetLayoutEventArgs())); } static readonly PropertyInfo previousContainerProperty = typeof(LayoutContent).GetProperty("PreviousContainer", BindingFlags.NonPublic | BindingFlags.Instance); diff --git a/ILSpy/ExtensionMethods.cs b/ILSpy/ExtensionMethods.cs index 1d49f41ada..bd460826c9 100644 --- a/ILSpy/ExtensionMethods.cs +++ b/ILSpy/ExtensionMethods.cs @@ -76,10 +76,11 @@ public static U[] SelectArray(this ICollection collection, Func f 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 93752eaefe..b79b79295a 100644 --- a/ILSpy/Languages/CSharpILMixedLanguage.cs +++ b/ILSpy/Languages/CSharpILMixedLanguage.cs @@ -34,6 +34,7 @@ using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.Util; +using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX.Extensions; @@ -43,13 +44,13 @@ namespace ICSharpCode.ILSpy [Export(typeof(Language))] [Shared] - class CSharpILMixedLanguage : ILLanguage + class CSharpILMixedLanguage(SettingsService settingsService, DockWorkspace dockWorkspace) : ILLanguage(dockWorkspace) { 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 5725e05556..c59a3fec66 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -38,6 +38,7 @@ 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 resourceFileHandlers; - string name = "C#"; bool showAllMembers = false; int transformCount = int.MaxValue; - public CSharpLanguage(IEnumerable resourceFileHandlers) - { - this.resourceFileHandlers = resourceFileHandlers.ToArray(); - } - #if DEBUG - internal static IEnumerable GetDebugLanguages(IReadOnlyCollection resourceFileHandlers) + internal static IEnumerable 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 @@ internal static IEnumerable GetDebugLanguages(IReadOnlyCollectio lastTransformName = "after " + transform.GetType().Name; transformCount++; } - yield return new CSharpLanguage(resourceFileHandlers) { + yield return new() { name = "C# - " + lastTransformName, showAllMembers = true }; @@ -364,15 +358,15 @@ public override void DecompileType(ITypeDefinition type, ITextOutput output, Dec 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().Single()); + AssemblyTreeModel.SelectNode(assemblyNode.Children.OfType().Single()); }); } @@ -436,7 +430,7 @@ public override ProjectId DecompileAssembly(LoadedAssembly assembly, ITextOutput { 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 @@ class ILSpyWholeProjectDecompiler : WholeProjectDecompiler { readonly LoadedAssembly assembly; readonly DecompilationOptions options; - private readonly IReadOnlyCollection resourceFileHandlers; - public ILSpyWholeProjectDecompiler(LoadedAssembly assembly, DecompilationOptions options, IReadOnlyCollection 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 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 @@ protected override IEnumerable WriteResourceToFile(string fileN } } - 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 @@ public override string GetEntityName(MetadataFile module, EntityHandle handle, b 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 @@ public override RichText GetRichTextTooltip(IEntity entity) 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/ILAstLanguage.cs b/ILSpy/Languages/ILAstLanguage.cs index b0f467b4b5..46ccd0fe4e 100644 --- a/ILSpy/Languages/ILAstLanguage.cs +++ b/ILSpy/Languages/ILAstLanguage.cs @@ -26,6 +26,7 @@ using ICSharpCode.Decompiler.IL.Transforms; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpyX; @@ -41,13 +42,6 @@ abstract class ILAstLanguage : Language { public event EventHandler StepperUpdated; - protected virtual void OnStepperUpdated(EventArgs e = null) - { - StepperUpdated?.Invoke(this, e ?? new EventArgs()); - } - - public Stepper Stepper { get; set; } = new Stepper(); - readonly string name; protected ILAstLanguage(string name) @@ -55,12 +49,19 @@ protected ILAstLanguage(string name) this.name = name; } + protected virtual void OnStepperUpdated(EventArgs e = null) + { + StepperUpdated?.Invoke(this, e ?? new EventArgs()); + } + + public Stepper Stepper { get; set; } = new Stepper(); + public override string Name { get { return name; } } - internal static IEnumerable GetDebugLanguages() + internal static IEnumerable GetDebugLanguages(DockWorkspace dockWorkspace) { yield return new TypedIL(); - yield return new BlockIL(CSharpDecompiler.GetILTransforms()); + yield return new BlockIL(CSharpDecompiler.GetILTransforms(), dockWorkspace); } public override string FileExtension { @@ -78,10 +79,8 @@ public override void DecompileMethod(IMethod method, ITextOutput output, Decompi output.WriteLine(); } - class TypedIL : ILAstLanguage + class TypedIL() : ILAstLanguage("Typed IL") { - public TypedIL() : base("Typed IL") { } - public override void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options) { base.DecompileMethod(method, output, options); @@ -96,15 +95,8 @@ public override void DecompileMethod(IMethod method, ITextOutput output, Decompi } } - class BlockIL : ILAstLanguage + class BlockIL(IReadOnlyList transforms, DockWorkspace dockWorkspace) : ILAstLanguage("ILAst") { - readonly IReadOnlyList transforms; - - public BlockIL(IReadOnlyList transforms) : base("ILAst") - { - this.transforms = transforms; - } - public override void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options) { base.DecompileMethod(method, output, options); @@ -146,7 +138,7 @@ public override void DecompileMethod(IMethod method, ITextOutput output, Decompi } } (output as ISmartTextOutput)?.AddButton(Images.ViewCode, "Show Steps", delegate { - Docking.DockWorkspace.Instance.ShowToolPane(DebugStepsPaneModel.PaneContentId); + dockWorkspace.ShowToolPane(DebugStepsPaneModel.PaneContentId); }); output.WriteLine(); il.WriteTo(output, DebugSteps.Options); diff --git a/ILSpy/Languages/ILLanguage.cs b/ILSpy/Languages/ILLanguage.cs index a857268f12..ffaa314854 100644 --- a/ILSpy/Languages/ILLanguage.cs +++ b/ILSpy/Languages/ILLanguage.cs @@ -31,6 +31,7 @@ using ICSharpCode.Decompiler.Util; using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.TextView; +using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpyX; namespace ICSharpCode.ILSpy @@ -44,7 +45,7 @@ namespace ICSharpCode.ILSpy /// [Export(typeof(Language))] [Shared] - public class ILLanguage : Language + public class ILLanguage(DockWorkspace dockWorkspace) : Language { protected bool detectControlStructure = true; @@ -58,7 +59,7 @@ public override string FileExtension { 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,8 @@ public override ProjectId DecompileAssembly(LoadedAssembly assembly, ITextOutput 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 26410fe243..c0ef74643c 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.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 /// public abstract class Language : ILanguage { + protected static SettingsService SettingsService { get; } = App.ExportProvider.GetExportedValue(); + + protected static AssemblyTreeModel AssemblyTreeModel { get; } = App.ExportProvider.GetExportedValue(); + + protected static ICollection ResourceFileHandlers { get; } = App.ExportProvider.GetExportedValues().ToArray(); + /// /// Gets the name of the language (as shown in the UI) /// diff --git a/ILSpy/Languages/LanguageService.cs b/ILSpy/Languages/LanguageService.cs index e060c117df..6c116b1ad6 100644 --- a/ILSpy/Languages/LanguageService.cs +++ b/ILSpy/Languages/LanguageService.cs @@ -21,34 +21,32 @@ 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.ILSpy.Docking; using ICSharpCode.ILSpyX; using TomsToolbox.Wpf; namespace ICSharpCode.ILSpy { + [Export] + [Shared] public class LanguageService : ObservableObjectBase { - public static readonly LanguageService Instance = new(App.ExportProvider.GetExportedValues(), App.ExportProvider.GetExportedValues(), SettingsService.Instance); - private readonly LanguageSettings languageSettings; - private readonly SettingsService settingsService; - public LanguageService(IEnumerable languages, IEnumerable resourceFileHandlers, SettingsService settingsService) + public LanguageService(IEnumerable languages, SettingsService settingsService, DockWorkspace dockWorkspace) { - this.settingsService = settingsService; languageSettings = settingsService.SessionSettings.LanguageSettings; var sortedLanguages = languages.ToList(); 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(ILAstLanguage.GetDebugLanguages(dockWorkspace)); + sortedLanguages.AddRange(CSharpLanguage.GetDebugLanguages()); #endif AllLanguages = sortedLanguages.AsReadOnly(); @@ -143,10 +141,5 @@ public LanguageVersion? LanguageVersion { languageSettings.LanguageVersionId = languageVersion?.Version; } } - - public DecompilationOptions CreateDecompilationOptions(TabPageModel tabPage) - { - return new(LanguageVersion, settingsService.DecompilerSettings, settingsService.DisplaySettings) { Progress = tabPage.Content as IProgress }; - } } } diff --git a/ILSpy/MainWindow.xaml b/ILSpy/MainWindow.xaml index bbefc63fc1..177dbe951b 100644 --- a/ILSpy/MainWindow.xaml +++ b/ILSpy/MainWindow.xaml @@ -18,6 +18,9 @@ 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" + xmlns:analyzers="clr-namespace:ICSharpCode.ILSpy.Analyzers" d:DataContext="{d:DesignInstance local:MainWindowViewModel}"> @@ -36,7 +39,7 @@ - + @@ -47,8 +50,9 @@ - - + + + @@ -60,7 +64,7 @@