Browse Source

Get rid of singletons, replace with DI: DockWorkspace

pull/3314/head
tom-englert 9 months ago
parent
commit
61b0714a4b
  1. 2
      ILSpy/App.xaml.cs
  2. 32
      ILSpy/AssemblyTree/AssemblyTreeModel.cs
  3. 11
      ILSpy/Commands/DecompileAllCommand.cs
  4. 15
      ILSpy/Commands/DecompileInNewViewCommand.cs
  5. 7
      ILSpy/Commands/DisassembleAllCommand.cs
  6. 7
      ILSpy/Commands/ExtractPackageEntryContextMenuEntry.cs
  7. 13
      ILSpy/Commands/GeneratePdbContextMenuEntry.cs
  8. 15
      ILSpy/Commands/Pdb2XmlCommand.cs
  9. 11
      ILSpy/Commands/SaveCodeContextMenuEntry.cs
  10. 5
      ILSpy/Commands/SaveCommand.cs
  11. 28
      ILSpy/Commands/ShowPane.cs
  12. 17
      ILSpy/Controls/ZoomScrollViewer.cs
  13. 8
      ILSpy/Docking/CloseAllDocumentsCommand.cs
  14. 47
      ILSpy/Docking/DockWorkspace.cs
  15. 3
      ILSpy/Languages/CSharpILMixedLanguage.cs
  16. 34
      ILSpy/Languages/ILAstLanguage.cs
  17. 3
      ILSpy/Languages/ILLanguage.cs
  18. 5
      ILSpy/Languages/LanguageService.cs
  19. 7
      ILSpy/MainWindowViewModel.cs
  20. 7
      ILSpy/Search/SearchPane.xaml.cs
  21. 16
      ILSpy/SolutionWriter.cs
  22. 3
      ILSpy/TaskHelper.cs
  23. 2
      ILSpy/TreeNodes/AssemblyTreeNode.cs
  24. 3
      ILSpy/TreeNodes/ILSpyTreeNode.cs
  25. 2
      ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs
  26. 2
      ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs
  27. 18
      ILSpy/Util/MenuService.cs
  28. 5
      ILSpy/ViewModels/PaneModel.cs
  29. 8
      ILSpy/Views/DebugSteps.xaml.cs

2
ILSpy/App.xaml.cs

@ -86,7 +86,7 @@ namespace ICSharpCode.ILSpy
if (!InitializeDependencyInjection(settingsService)) if (!InitializeDependencyInjection(settingsService))
{ {
// There is something completely wrong with DI, probably some service registration is missing => nothing we can do to recover, so stop and shut down. // There is something completely wrong with DI, probably some service registration is missing => nothing we can do to recover, so stop and shut down.
Exit += (_, _) => MessageBox.Show(StartupExceptions.FormatExceptions(), "Sorry we crashed!"); Exit += (_, _) => MessageBox.Show(StartupExceptions.FormatExceptions(), "Sorry we crashed!", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK, MessageBoxOptions.DefaultDesktopOnly);
Shutdown(1); Shutdown(1);
return; return;
} }

32
ILSpy/AssemblyTree/AssemblyTreeModel.cs

@ -264,7 +264,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
{ {
AvalonEditTextOutput output = new AvalonEditTextOutput(); AvalonEditTextOutput output = new AvalonEditTextOutput();
output.Write($"Cannot find '{navigateTo}' in command line specified assemblies."); output.Write($"Cannot find '{navigateTo}' in command line specified assemblies.");
DockWorkspace.Instance.ShowText(output); DockWorkspace.ShowText(output);
} }
} }
else if (relevantAssemblies.Count == 1) else if (relevantAssemblies.Count == 1)
@ -304,7 +304,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
} }
else else
{ {
DockWorkspace.Instance.ActiveTabPage.ShowTextView(aboutPage.Display); DockWorkspace.ActiveTabPage.ShowTextView(aboutPage.Display);
} }
} }
} }
@ -405,8 +405,8 @@ namespace ICSharpCode.ILSpy.AssemblyTree
{ {
output.Title = "Startup errors"; output.Title = "Startup errors";
DockWorkspace.Instance.AddTabPage(); DockWorkspace.AddTabPage();
DockWorkspace.Instance.ShowText(output); DockWorkspace.ShowText(output);
} }
} }
@ -524,7 +524,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
if (inNewTabPage) if (inNewTabPage)
{ {
DockWorkspace.Instance.AddTabPage(); DockWorkspace.AddTabPage();
SelectedItem = null; SelectedItem = null;
} }
@ -739,7 +739,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
} }
else else
{ {
var activeTabPage = DockWorkspace.Instance.ActiveTabPage; var activeTabPage = DockWorkspace.ActiveTabPage;
if (!isNavigatingHistory) if (!isNavigatingHistory)
{ {
@ -787,7 +787,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
public void DecompileSelectedNodes(DecompilerTextViewState? newState = null) public void DecompileSelectedNodes(DecompilerTextViewState? newState = null)
{ {
var activeTabPage = DockWorkspace.Instance.ActiveTabPage; var activeTabPage = DockWorkspace.ActiveTabPage;
activeTabPage.SupportsLanguageSwitching = true; activeTabPage.SupportsLanguageSwitching = true;
@ -809,7 +809,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
public void RefreshDecompiledView() public void RefreshDecompiledView()
{ {
DecompileSelectedNodes(DockWorkspace.Instance.ActiveTabPage.GetState() as DecompilerTextViewState); DecompileSelectedNodes(DockWorkspace.ActiveTabPage.GetState() as DecompilerTextViewState);
} }
public Language CurrentLanguage => languageService.Language; public Language CurrentLanguage => languageService.Language;
@ -830,7 +830,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
{ {
isNavigatingHistory = true; isNavigatingHistory = true;
TabPageModel tabPage = DockWorkspace.Instance.ActiveTabPage; TabPageModel tabPage = DockWorkspace.ActiveTabPage;
var state = tabPage.GetState(); var state = tabPage.GetState();
if (state != null) if (state != null)
history.UpdateCurrent(new NavigationState(tabPage, state)); history.UpdateCurrent(new NavigationState(tabPage, state));
@ -838,10 +838,10 @@ namespace ICSharpCode.ILSpy.AssemblyTree
TabPageModel activeTabPage = newState.TabPage; TabPageModel activeTabPage = newState.TabPage;
if (!DockWorkspace.Instance.TabPages.Contains(activeTabPage)) if (!DockWorkspace.TabPages.Contains(activeTabPage))
DockWorkspace.Instance.AddTabPage(activeTabPage); DockWorkspace.AddTabPage(activeTabPage);
else else
DockWorkspace.Instance.ActiveTabPage = activeTabPage; DockWorkspace.ActiveTabPage = activeTabPage;
SelectNodes(newState.TreeNodes); SelectNodes(newState.TreeNodes);
} }
@ -861,13 +861,13 @@ namespace ICSharpCode.ILSpy.AssemblyTree
{ {
if (inNewTabPage) if (inNewTabPage)
{ {
DockWorkspace.Instance.AddTabPage(); DockWorkspace.AddTabPage();
} }
if (e.Uri.Host == "aboutpage") if (e.Uri.Host == "aboutpage")
{ {
RecordHistory(); RecordHistory();
DockWorkspace.Instance.ActiveTabPage.ShowTextView(aboutPage.Display); DockWorkspace.ActiveTabPage.ShowTextView(aboutPage.Display);
e.Handled = true; e.Handled = true;
return; return;
} }
@ -891,7 +891,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
} }
} }
RecordHistory(); RecordHistory();
DockWorkspace.Instance.ShowText(output); DockWorkspace.ShowText(output);
e.Handled = true; e.Handled = true;
} }
@ -899,7 +899,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
{ {
if (isNavigatingHistory) if (isNavigatingHistory)
return; return;
TabPageModel tabPage = DockWorkspace.Instance.ActiveTabPage; TabPageModel tabPage = DockWorkspace.ActiveTabPage;
var currentState = tabPage.GetState(); var currentState = tabPage.GetState();
if (currentState != null) if (currentState != null)
history.UpdateCurrent(new NavigationState(tabPage, currentState)); history.UpdateCurrent(new NavigationState(tabPage, currentState));

11
ILSpy/Commands/DecompileAllCommand.cs

@ -38,7 +38,7 @@ namespace ICSharpCode.ILSpy
{ {
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDecompile), MenuCategory = nameof(Resources.Open), MenuOrder = 2.5)] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDecompile), MenuCategory = nameof(Resources.Open), MenuOrder = 2.5)]
[Shared] [Shared]
sealed class DecompileAllCommand(AssemblyTreeModel assemblyTreeModel, LanguageService languageService) : SimpleCommand sealed class DecompileAllCommand(AssemblyTreeModel assemblyTreeModel, DockWorkspace dockWorkspace) : SimpleCommand
{ {
public override bool CanExecute(object parameter) public override bool CanExecute(object parameter)
{ {
@ -47,7 +47,7 @@ namespace ICSharpCode.ILSpy
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => { dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
AvalonEditTextOutput output = new AvalonEditTextOutput(); AvalonEditTextOutput output = new AvalonEditTextOutput();
Parallel.ForEach( Parallel.ForEach(
Partitioner.Create(assemblyTreeModel.AssemblyList.GetAssemblies(), loadBalance: true), Partitioner.Create(assemblyTreeModel.AssemblyList.GetAssemblies(), loadBalance: true),
@ -61,7 +61,7 @@ namespace ICSharpCode.ILSpy
{ {
try try
{ {
var options = DockWorkspace.Instance.ActiveTabPage.CreateDecompilationOptions(); var options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions();
options.CancellationToken = ct; options.CancellationToken = ct;
options.FullDecompilation = true; options.FullDecompilation = true;
new CSharpLanguage().DecompileAssembly(asm, new PlainTextOutput(writer), options); new CSharpLanguage().DecompileAssembly(asm, new PlainTextOutput(writer), options);
@ -85,20 +85,19 @@ namespace ICSharpCode.ILSpy
} }
}); });
return output; 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)] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDecompile100x), MenuCategory = nameof(Resources.Open), MenuOrder = 2.6)]
[Shared] [Shared]
sealed class Decompile100TimesCommand(AssemblyTreeModel assemblyTreeModel, LanguageService languageService) : SimpleCommand sealed class Decompile100TimesCommand(AssemblyTreeModel assemblyTreeModel, LanguageService languageService, DockWorkspace dockWorkspace) : SimpleCommand
{ {
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
const int numRuns = 100; const int numRuns = 100;
var language = languageService.Language; var language = languageService.Language;
var nodes = assemblyTreeModel.SelectedNodes.ToArray(); var nodes = assemblyTreeModel.SelectedNodes.ToArray();
DockWorkspace dockWorkspace = DockWorkspace.Instance;
var options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions(); var options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions();
dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => { dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
options.CancellationToken = ct; options.CancellationToken = ct;

15
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)] [ExportContextMenuEntry(Header = nameof(Resources.DecompileToNewPanel), InputGestureText = "MMB", Icon = "images/Search", Category = nameof(Resources.Analyze), Order = 90)]
[Shared] [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) public bool IsVisible(TextViewContext context)
{ {
return context.SelectedTreeNodes != null || context.Reference?.Reference is IEntity; return context.SelectedTreeNodes != null || context.Reference?.Reference is IEntity;
@ -56,11 +49,11 @@ namespace ICSharpCode.ILSpy.Commands
public void Execute(TextViewContext context) public void Execute(TextViewContext context)
{ {
var activePane = DockWorkspace.Instance.ActivePane; var activePane = dockWorkspace.ActivePane;
DecompileNodes(GetNodes(context).ToArray()); DecompileNodes(GetNodes(context).ToArray());
DockWorkspace.Instance.ActivePane = activePane; dockWorkspace.ActivePane = activePane;
} }
IEnumerable<ILSpyTreeNode> GetNodes(TextViewContext context) IEnumerable<ILSpyTreeNode> GetNodes(TextViewContext context)
@ -98,7 +91,7 @@ namespace ICSharpCode.ILSpy.Commands
if (nodes.Length == 0) if (nodes.Length == 0)
return; return;
DockWorkspace.Instance.AddTabPage(); dockWorkspace.AddTabPage();
if (assemblyTreeModel.SelectedItems.SequenceEqual(nodes)) if (assemblyTreeModel.SelectedItems.SequenceEqual(nodes))
assemblyTreeModel.DecompileSelectedNodes(); assemblyTreeModel.DecompileSelectedNodes();

7
ILSpy/Commands/DisassembleAllCommand.cs

@ -25,6 +25,7 @@ using System.Diagnostics;
using System.Threading.Tasks; using System.Threading.Tasks;
using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpy.ViewModels;
@ -33,7 +34,7 @@ namespace ICSharpCode.ILSpy
{ {
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDisassemble), MenuCategory = nameof(Resources.Open), MenuOrder = 2.5)] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDisassemble), MenuCategory = nameof(Resources.Open), MenuOrder = 2.5)]
[Shared] [Shared]
sealed class DisassembleAllCommand(AssemblyTreeModel assemblyTreeModel, LanguageService languageService) : SimpleCommand sealed class DisassembleAllCommand(AssemblyTreeModel assemblyTreeModel, DockWorkspace dockWorkspace) : SimpleCommand
{ {
public override bool CanExecute(object parameter) public override bool CanExecute(object parameter)
{ {
@ -42,8 +43,6 @@ namespace ICSharpCode.ILSpy
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
var dockWorkspace = Docking.DockWorkspace.Instance;
dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => { dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
AvalonEditTextOutput output = new(); AvalonEditTextOutput output = new();
Parallel.ForEach( Parallel.ForEach(
@ -61,7 +60,7 @@ namespace ICSharpCode.ILSpy
var options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions(); var options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions();
options.FullDecompilation = true; options.FullDecompilation = true;
options.CancellationToken = ct; options.CancellationToken = ct;
new ILLanguage().DecompileAssembly(asm, new Decompiler.PlainTextOutput(writer), options); new ILLanguage(dockWorkspace).DecompileAssembly(asm, new Decompiler.PlainTextOutput(writer), options);
} }
catch (Exception ex) catch (Exception ex)
{ {

7
ILSpy/Commands/ExtractPackageEntryContextMenuEntry.cs

@ -25,6 +25,7 @@ using System.Threading.Tasks;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler; using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
@ -36,7 +37,7 @@ namespace ICSharpCode.ILSpy
{ {
[ExportContextMenuEntry(Header = nameof(Resources.ExtractPackageEntry), Category = nameof(Resources.Save), Icon = "Images/Save")] [ExportContextMenuEntry(Header = nameof(Resources.ExtractPackageEntry), Category = nameof(Resources.Save), Icon = "Images/Save")]
[Shared] [Shared]
sealed class ExtractPackageEntryContextMenuEntry : IContextMenuEntry sealed class ExtractPackageEntryContextMenuEntry(DockWorkspace dockWorkspace) : IContextMenuEntry
{ {
public void Execute(TextViewContext context) public void Execute(TextViewContext context)
{ {
@ -61,7 +62,7 @@ namespace ICSharpCode.ILSpy
if (selectedNodes.Length > 1) if (selectedNodes.Length > 1)
outputFolderOrFileName = Path.GetDirectoryName(outputFolderOrFileName); outputFolderOrFileName = Path.GetDirectoryName(outputFolderOrFileName);
Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => { dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
AvalonEditTextOutput output = new AvalonEditTextOutput(); AvalonEditTextOutput output = new AvalonEditTextOutput();
Stopwatch stopwatch = Stopwatch.StartNew(); Stopwatch stopwatch = Stopwatch.StartNew();
stopwatch.Stop(); stopwatch.Stop();
@ -83,7 +84,7 @@ namespace ICSharpCode.ILSpy
output.AddButton(null, Resources.OpenExplorer, delegate { Process.Start("explorer", "/select,\"" + fileName + "\""); }); output.AddButton(null, Resources.OpenExplorer, delegate { Process.Start("explorer", "/select,\"" + fileName + "\""); });
output.WriteLine(); output.WriteLine();
return output; return output;
}, ct)).Then(output => Docking.DockWorkspace.Instance.ShowText(output)).HandleExceptions(); }, ct)).Then(dockWorkspace.ShowText).HandleExceptions();
} }
void SaveEntry(ITextOutput output, PackageEntry entry, string targetFileName) void SaveEntry(ITextOutput output, PackageEntry entry, string targetFileName)

13
ILSpy/Commands/GeneratePdbContextMenuEntry.cs

@ -43,14 +43,14 @@ namespace ICSharpCode.ILSpy
{ {
[ExportContextMenuEntry(Header = nameof(Resources.GeneratePortable))] [ExportContextMenuEntry(Header = nameof(Resources.GeneratePortable))]
[Shared] [Shared]
class GeneratePdbContextMenuEntry(LanguageService languageService) : IContextMenuEntry class GeneratePdbContextMenuEntry(LanguageService languageService, DockWorkspace dockWorkspace) : IContextMenuEntry
{ {
public void Execute(TextViewContext context) public void Execute(TextViewContext context)
{ {
var assembly = (context.SelectedTreeNodes?.FirstOrDefault() as AssemblyTreeNode)?.LoadedAssembly; var assembly = (context.SelectedTreeNodes?.FirstOrDefault() as AssemblyTreeNode)?.LoadedAssembly;
if (assembly == null) if (assembly == null)
return; return;
GeneratePdbForAssembly(assembly, languageService); GeneratePdbForAssembly(assembly, languageService, dockWorkspace);
} }
public bool IsEnabled(TextViewContext context) => true; public bool IsEnabled(TextViewContext context) => true;
@ -62,7 +62,7 @@ namespace ICSharpCode.ILSpy
&& tn.LoadedAssembly.IsLoadedAsValidAssembly; && tn.LoadedAssembly.IsLoadedAsValidAssembly;
} }
internal static void GeneratePdbForAssembly(LoadedAssembly assembly, LanguageService languageService) internal static void GeneratePdbForAssembly(LoadedAssembly assembly, LanguageService languageService, DockWorkspace dockWorkspace)
{ {
var file = assembly.GetMetadataFileOrNull() as PEFile; var file = assembly.GetMetadataFileOrNull() as PEFile;
if (!PortablePdbWriter.HasCodeViewDebugDirectoryEntry(file)) if (!PortablePdbWriter.HasCodeViewDebugDirectoryEntry(file))
@ -76,7 +76,6 @@ namespace ICSharpCode.ILSpy
dlg.InitialDirectory = Path.GetDirectoryName(assembly.FileName); dlg.InitialDirectory = Path.GetDirectoryName(assembly.FileName);
if (dlg.ShowDialog() != true) if (dlg.ShowDialog() != true)
return; return;
DockWorkspace dockWorkspace = DockWorkspace.Instance;
DecompilationOptions options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions(); DecompilationOptions options = dockWorkspace.ActiveTabPage.CreateDecompilationOptions();
string fileName = dlg.FileName; string fileName = dlg.FileName;
dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => { dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
@ -104,13 +103,13 @@ namespace ICSharpCode.ILSpy
output.AddButton(null, Resources.OpenExplorer, delegate { Process.Start("explorer", "/select,\"" + fileName + "\""); }); output.AddButton(null, Resources.OpenExplorer, delegate { Process.Start("explorer", "/select,\"" + fileName + "\""); });
output.WriteLine(); output.WriteLine();
return output; 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))] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.GeneratePortable), MenuCategory = nameof(Resources.Save))]
[Shared] [Shared]
class GeneratePdbMainMenuEntry(AssemblyTreeModel assemblyTreeModel, LanguageService languageService) : SimpleCommand class GeneratePdbMainMenuEntry(AssemblyTreeModel assemblyTreeModel, LanguageService languageService, DockWorkspace dockWorkspace) : SimpleCommand
{ {
public override bool CanExecute(object parameter) public override bool CanExecute(object parameter)
{ {
@ -124,7 +123,7 @@ namespace ICSharpCode.ILSpy
var assembly = (assemblyTreeModel.SelectedNodes?.FirstOrDefault() as AssemblyTreeNode)?.LoadedAssembly; var assembly = (assemblyTreeModel.SelectedNodes?.FirstOrDefault() as AssemblyTreeNode)?.LoadedAssembly;
if (assembly == null) if (assembly == null)
return; return;
GeneratePdbContextMenuEntry.GeneratePdbForAssembly(assembly, languageService); GeneratePdbContextMenuEntry.GeneratePdbForAssembly(assembly, languageService, dockWorkspace);
} }
} }
} }

15
ILSpy/Commands/Pdb2XmlCommand.cs

@ -27,6 +27,7 @@ using System.Threading.Tasks;
using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
@ -37,7 +38,7 @@ namespace ICSharpCode.ILSpy
{ {
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDumpPDBAsXML), MenuCategory = nameof(Resources.Open), MenuOrder = 2.6)] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.DEBUGDumpPDBAsXML), MenuCategory = nameof(Resources.Open), MenuOrder = 2.6)]
[Shared] [Shared]
sealed class Pdb2XmlCommand(AssemblyTreeModel assemblyTreeModel) : SimpleCommand sealed class Pdb2XmlCommand(AssemblyTreeModel assemblyTreeModel, DockWorkspace dockWorkspace) : SimpleCommand
{ {
public override bool CanExecute(object parameter) public override bool CanExecute(object parameter)
{ {
@ -48,14 +49,14 @@ namespace ICSharpCode.ILSpy
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
Execute(assemblyTreeModel.SelectedNodes.OfType<AssemblyTreeNode>()); Execute(assemblyTreeModel.SelectedNodes.OfType<AssemblyTreeNode>(), dockWorkspace);
} }
internal static void Execute(IEnumerable<AssemblyTreeNode> nodes) internal static void Execute(IEnumerable<AssemblyTreeNode> nodes, DockWorkspace dockWorkspace)
{ {
var highlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml"); var highlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml");
var options = PdbToXmlOptions.IncludeEmbeddedSources | PdbToXmlOptions.IncludeMethodSpans | PdbToXmlOptions.IncludeTokens; var options = PdbToXmlOptions.IncludeEmbeddedSources | PdbToXmlOptions.IncludeMethodSpans | PdbToXmlOptions.IncludeTokens;
Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => { dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
AvalonEditTextOutput output = new AvalonEditTextOutput(); AvalonEditTextOutput output = new AvalonEditTextOutput();
var writer = new TextOutputWriter(output); var writer = new TextOutputWriter(output);
foreach (var node in nodes) foreach (var node in nodes)
@ -68,17 +69,17 @@ namespace ICSharpCode.ILSpy
PdbToXmlConverter.ToXml(writer, pdbStream, peStream, options); PdbToXmlConverter.ToXml(writer, pdbStream, peStream, options);
} }
return output; 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))] [ExportContextMenuEntry(Header = nameof(Resources.DEBUGDumpPDBAsXML))]
[Shared] [Shared]
class Pdb2XmlCommandContextMenuEntry : IContextMenuEntry class Pdb2XmlCommandContextMenuEntry(DockWorkspace dockWorkspace) : IContextMenuEntry
{ {
public void Execute(TextViewContext context) public void Execute(TextViewContext context)
{ {
Pdb2XmlCommand.Execute(context.SelectedTreeNodes.OfType<AssemblyTreeNode>()); Pdb2XmlCommand.Execute(context.SelectedTreeNodes.OfType<AssemblyTreeNode>(), dockWorkspace);
} }
public bool IsEnabled(TextViewContext context) => true; public bool IsEnabled(TextViewContext context) => true;

11
ILSpy/Commands/SaveCodeContextMenuEntry.cs

@ -23,6 +23,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpy.ViewModels;
@ -35,11 +36,11 @@ namespace ICSharpCode.ILSpy.TextView
{ {
[ExportContextMenuEntry(Header = nameof(Resources._SaveCode), Category = nameof(Resources.Save), Icon = "Images/Save")] [ExportContextMenuEntry(Header = nameof(Resources._SaveCode), Category = nameof(Resources.Save), Icon = "Images/Save")]
[Shared] [Shared]
sealed class SaveCodeContextMenuEntry(LanguageService languageService) : IContextMenuEntry sealed class SaveCodeContextMenuEntry(LanguageService languageService, DockWorkspace dockWorkspace) : IContextMenuEntry
{ {
public void Execute(TextViewContext context) public void Execute(TextViewContext context)
{ {
Execute(context.SelectedTreeNodes, languageService); Execute(context.SelectedTreeNodes, languageService, dockWorkspace);
} }
public bool IsEnabled(TextViewContext context) => true; public bool IsEnabled(TextViewContext context) => true;
@ -57,10 +58,8 @@ namespace ICSharpCode.ILSpy.TextView
|| (selectedNodes.Count > 1 && (selectedNodes.All(n => n is AssemblyTreeNode) || selectedNodes.All(n => n is IMemberTreeNode))); || (selectedNodes.Count > 1 && (selectedNodes.All(n => n is AssemblyTreeNode) || selectedNodes.All(n => n is IMemberTreeNode)));
} }
public static void Execute(IReadOnlyList<SharpTreeNode> selectedNodes, LanguageService languageService) public static void Execute(IReadOnlyList<SharpTreeNode> selectedNodes, LanguageService languageService, DockWorkspace dockWorkspace)
{ {
var dockWorkspace = Docking.DockWorkspace.Instance;
var currentLanguage = languageService.Language; var currentLanguage = languageService.Language;
var tabPage = dockWorkspace.ActiveTabPage; var tabPage = dockWorkspace.ActiveTabPage;
tabPage.ShowTextView(textView => { tabPage.ShowTextView(textView => {
@ -80,7 +79,7 @@ namespace ICSharpCode.ILSpy.TextView
var assemblies = selectedNodes.OfType<AssemblyTreeNode>() var assemblies = selectedNodes.OfType<AssemblyTreeNode>()
.Select(n => n.LoadedAssembly) .Select(n => n.LoadedAssembly)
.Where(a => a.IsLoadedAsValidAssembly).ToArray(); .Where(a => a.IsLoadedAsValidAssembly).ToArray();
SolutionWriter.CreateSolution(textView, selectedPath, currentLanguage, assemblies); SolutionWriter.CreateSolution(tabPage, textView, selectedPath, currentLanguage, assemblies);
} }
return; return;
} }

5
ILSpy/Commands/SaveCommand.cs

@ -21,6 +21,7 @@ using System.Linq;
using System.Windows.Input; using System.Windows.Input;
using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
@ -28,7 +29,7 @@ namespace ICSharpCode.ILSpy
{ {
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources._SaveCode), MenuIcon = "Images/Save", MenuCategory = nameof(Resources.Save), MenuOrder = 0)] [ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources._SaveCode), MenuIcon = "Images/Save", MenuCategory = nameof(Resources.Save), MenuOrder = 0)]
[Shared] [Shared]
sealed class SaveCommand(AssemblyTreeModel assemblyTreeModel, LanguageService languageService) : CommandWrapper(ApplicationCommands.Save) sealed class SaveCommand(AssemblyTreeModel assemblyTreeModel, LanguageService languageService, DockWorkspace dockWorkspace) : CommandWrapper(ApplicationCommands.Save)
{ {
protected override void OnCanExecute(object sender, CanExecuteRoutedEventArgs e) protected override void OnCanExecute(object sender, CanExecuteRoutedEventArgs e)
{ {
@ -38,7 +39,7 @@ namespace ICSharpCode.ILSpy
protected override void OnExecute(object sender, ExecutedRoutedEventArgs e) protected override void OnExecute(object sender, ExecutedRoutedEventArgs e)
{ {
SaveCodeContextMenuEntry.Execute(assemblyTreeModel.SelectedNodes.ToList(), languageService); SaveCodeContextMenuEntry.Execute(assemblyTreeModel.SelectedNodes.ToList(), languageService, dockWorkspace);
} }
} }
} }

28
ILSpy/Commands/ShowPane.cs

@ -3,39 +3,23 @@ using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy.Commands 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) 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) 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 // 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 // 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; dockWorkspace.ActiveTabPage = null;
workspace.ActiveTabPage = model; dockWorkspace.ActiveTabPage = model;
} }
} }
} }

17
ILSpy/Controls/ZoomScrollViewer.cs

@ -176,21 +176,4 @@ namespace ICSharpCode.ILSpy.Controls
return 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();
}
}
} }

8
ILSpy/Docking/CloseAllDocumentsCommand.cs

@ -6,21 +6,21 @@ namespace ICSharpCode.ILSpy.Docking
{ {
[ExportMainMenuCommand(Header = nameof(Resources.Window_CloseAllDocuments), ParentMenuID = nameof(Resources._Window))] [ExportMainMenuCommand(Header = nameof(Resources.Window_CloseAllDocuments), ParentMenuID = nameof(Resources._Window))]
[Shared] [Shared]
class CloseAllDocumentsCommand : SimpleCommand class CloseAllDocumentsCommand(DockWorkspace dockWorkspace) : SimpleCommand
{ {
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
DockWorkspace.Instance.CloseAllTabs(); dockWorkspace.CloseAllTabs();
} }
} }
[ExportMainMenuCommand(Header = nameof(Resources.Window_ResetLayout), ParentMenuID = nameof(Resources._Window))] [ExportMainMenuCommand(Header = nameof(Resources.Window_ResetLayout), ParentMenuID = nameof(Resources._Window))]
[Shared] [Shared]
class ResetLayoutCommand : SimpleCommand class ResetLayoutCommand(DockWorkspace dockWorkspace) : SimpleCommand
{ {
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
DockWorkspace.Instance.ResetLayout(); dockWorkspace.ResetLayout();
} }
} }
} }

47
ILSpy/Docking/DockWorkspace.cs

@ -20,6 +20,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Composition;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading; using System.Threading;
@ -43,37 +44,33 @@ using TomsToolbox.Wpf;
namespace ICSharpCode.ILSpy.Docking namespace ICSharpCode.ILSpy.Docking
{ {
[Export]
[Shared]
public class DockWorkspace : ObservableObject, ILayoutUpdateStrategy public class DockWorkspace : ObservableObject, ILayoutUpdateStrategy
{ {
private static readonly IExportProvider exportProvider = App.ExportProvider; private readonly IExportProvider exportProvider;
private static SettingsService SettingsService => exportProvider.GetExportedValue<SettingsService>(); private SettingsService SettingsService { get; }
private static LanguageService LanguageService => exportProvider.GetExportedValue<LanguageService>(); private LanguageService LanguageService => exportProvider.GetExportedValue<LanguageService>();
private static SessionSettings SessionSettings => SettingsService.SessionSettings; private SessionSettings SessionSettings { get; }
public static readonly DockWorkspace Instance = new();
private readonly ObservableCollection<TabPageModel> tabPages = []; private readonly ObservableCollection<TabPageModel> tabPages = [];
private DockingManager DockingManager => exportProvider.GetExportedValue<DockingManager>(); private DockingManager DockingManager => exportProvider.GetExportedValue<DockingManager>();
AssemblyTreeModel AssemblyTreeModel => exportProvider.GetExportedValue<AssemblyTreeModel>(); private AssemblyTreeModel AssemblyTreeModel => exportProvider.GetExportedValue<AssemblyTreeModel>();
private DockWorkspace() public DockWorkspace(SettingsService settingsService, IExportProvider exportProvider)
{ {
this.tabPages.CollectionChanged += TabPages_CollectionChanged; this.exportProvider = exportProvider;
TabPages = new(tabPages);
ToolPanes = exportProvider SettingsService = settingsService;
.GetExportedValues<ToolPaneModel>("ToolPane") SessionSettings = settingsService.SessionSettings;
.OrderBy(item => item.Title)
.ToArray()
.AsReadOnly();
// Make sure there is at least one tab open this.tabPages.CollectionChanged += TabPages_CollectionChanged;
AddTabPage(); TabPages = new(tabPages);
MessageBus<CurrentAssemblyListChangedEventArgs>.Subscribers += (sender, e) => CurrentAssemblyList_Changed(sender, e); MessageBus<CurrentAssemblyListChangedEventArgs>.Subscribers += (sender, e) => CurrentAssemblyList_Changed(sender, e);
} }
@ -135,7 +132,11 @@ namespace ICSharpCode.ILSpy.Docking
public ReadOnlyObservableCollection<TabPageModel> TabPages { get; } public ReadOnlyObservableCollection<TabPageModel> TabPages { get; }
public ReadOnlyCollection<ToolPaneModel> ToolPanes { get; } public ReadOnlyCollection<ToolPaneModel> ToolPanes => exportProvider
.GetExportedValues<ToolPaneModel>("ToolPane")
.OrderBy(item => item.Title)
.ToArray()
.AsReadOnly();
public bool ShowToolPane(string contentId) public bool ShowToolPane(string contentId)
{ {
@ -188,15 +189,15 @@ namespace ICSharpCode.ILSpy.Docking
} }
public PaneModel ActivePane { public PaneModel ActivePane {
get => DockingManager?.ActiveContent as PaneModel; get => DockingManager.ActiveContent as PaneModel;
set { set => DockingManager.ActiveContent = value;
if (DockingManager is not null)
DockingManager.ActiveContent = value;
}
} }
public void InitializeLayout() public void InitializeLayout()
{ {
// Make sure there is at least one tab open
AddTabPage();
DockingManager.LayoutUpdateStrategy = this; DockingManager.LayoutUpdateStrategy = this;
XmlLayoutSerializer serializer = new XmlLayoutSerializer(DockingManager); XmlLayoutSerializer serializer = new XmlLayoutSerializer(DockingManager);
serializer.LayoutSerializationCallback += LayoutSerializationCallback; serializer.LayoutSerializationCallback += LayoutSerializationCallback;

3
ILSpy/Languages/CSharpILMixedLanguage.cs

@ -34,6 +34,7 @@ using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpyX.Extensions; using ICSharpCode.ILSpyX.Extensions;
@ -43,7 +44,7 @@ namespace ICSharpCode.ILSpy
[Export(typeof(Language))] [Export(typeof(Language))]
[Shared] [Shared]
class CSharpILMixedLanguage(SettingsService settingsService) : ILLanguage class CSharpILMixedLanguage(SettingsService settingsService, DockWorkspace dockWorkspace) : ILLanguage(dockWorkspace)
{ {
public override string Name => "IL with C#"; public override string Name => "IL with C#";

34
ILSpy/Languages/ILAstLanguage.cs

@ -26,6 +26,7 @@ using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.IL.Transforms; using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
@ -41,13 +42,6 @@ namespace ICSharpCode.ILSpy
{ {
public event EventHandler StepperUpdated; 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; readonly string name;
protected ILAstLanguage(string name) protected ILAstLanguage(string name)
@ -55,12 +49,19 @@ namespace ICSharpCode.ILSpy
this.name = 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; } } public override string Name { get { return name; } }
internal static IEnumerable<ILAstLanguage> GetDebugLanguages() internal static IEnumerable<ILAstLanguage> GetDebugLanguages(DockWorkspace dockWorkspace)
{ {
yield return new TypedIL(); yield return new TypedIL();
yield return new BlockIL(CSharpDecompiler.GetILTransforms()); yield return new BlockIL(CSharpDecompiler.GetILTransforms(), dockWorkspace);
} }
public override string FileExtension { public override string FileExtension {
@ -78,10 +79,8 @@ namespace ICSharpCode.ILSpy
output.WriteLine(); 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) public override void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options)
{ {
base.DecompileMethod(method, output, options); base.DecompileMethod(method, output, options);
@ -96,15 +95,8 @@ namespace ICSharpCode.ILSpy
} }
} }
class BlockIL : ILAstLanguage class BlockIL(IReadOnlyList<IILTransform> transforms, DockWorkspace dockWorkspace) : ILAstLanguage("ILAst")
{ {
readonly IReadOnlyList<IILTransform> transforms;
public BlockIL(IReadOnlyList<IILTransform> transforms) : base("ILAst")
{
this.transforms = transforms;
}
public override void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options) public override void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options)
{ {
base.DecompileMethod(method, output, options); base.DecompileMethod(method, output, options);
@ -146,7 +138,7 @@ namespace ICSharpCode.ILSpy
} }
} }
(output as ISmartTextOutput)?.AddButton(Images.ViewCode, "Show Steps", delegate { (output as ISmartTextOutput)?.AddButton(Images.ViewCode, "Show Steps", delegate {
Docking.DockWorkspace.Instance.ShowToolPane(DebugStepsPaneModel.PaneContentId); dockWorkspace.ShowToolPane(DebugStepsPaneModel.PaneContentId);
}); });
output.WriteLine(); output.WriteLine();
il.WriteTo(output, DebugSteps.Options); il.WriteTo(output, DebugSteps.Options);

3
ILSpy/Languages/ILLanguage.cs

@ -45,7 +45,7 @@ namespace ICSharpCode.ILSpy
/// </remarks> /// </remarks>
[Export(typeof(Language))] [Export(typeof(Language))]
[Shared] [Shared]
public class ILLanguage : Language public class ILLanguage(DockWorkspace dockWorkspace) : Language
{ {
protected bool detectControlStructure = true; protected bool detectControlStructure = true;
@ -199,7 +199,6 @@ namespace ICSharpCode.ILSpy
public override RichText GetRichTextTooltip(IEntity entity) public override RichText GetRichTextTooltip(IEntity entity)
{ {
var output = new AvalonEditTextOutput() { IgnoreNewLineAndIndent = true }; var output = new AvalonEditTextOutput() { IgnoreNewLineAndIndent = true };
var dockWorkspace = DockWorkspace.Instance;
var disasm = CreateDisassembler(output, dockWorkspace.ActiveTabPage.CreateDecompilationOptions()); var disasm = CreateDisassembler(output, dockWorkspace.ActiveTabPage.CreateDecompilationOptions());
MetadataFile module = entity.ParentModule?.MetadataFile; MetadataFile module = entity.ParentModule?.MetadataFile;

5
ILSpy/Languages/LanguageService.cs

@ -24,6 +24,7 @@ using System.Collections.ObjectModel;
using System.Composition; using System.Composition;
using System.Linq; using System.Linq;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
using TomsToolbox.Wpf; using TomsToolbox.Wpf;
@ -36,7 +37,7 @@ namespace ICSharpCode.ILSpy
{ {
private readonly LanguageSettings languageSettings; private readonly LanguageSettings languageSettings;
public LanguageService(IEnumerable<Language> languages, SettingsService settingsService) public LanguageService(IEnumerable<Language> languages, SettingsService settingsService, DockWorkspace dockWorkspace)
{ {
languageSettings = settingsService.SessionSettings.LanguageSettings; languageSettings = settingsService.SessionSettings.LanguageSettings;
@ -44,7 +45,7 @@ namespace ICSharpCode.ILSpy
sortedLanguages.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.Ordinal)); sortedLanguages.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.Ordinal));
#if DEBUG #if DEBUG
sortedLanguages.AddRange(ILAstLanguage.GetDebugLanguages()); sortedLanguages.AddRange(ILAstLanguage.GetDebugLanguages(dockWorkspace));
sortedLanguages.AddRange(CSharpLanguage.GetDebugLanguages()); sortedLanguages.AddRange(CSharpLanguage.GetDebugLanguages());
#endif #endif
AllLanguages = sortedLanguages.AsReadOnly(); AllLanguages = sortedLanguages.AsReadOnly();

7
ILSpy/MainWindowViewModel.cs

@ -29,11 +29,14 @@ namespace ICSharpCode.ILSpy
{ {
[Export] [Export]
[Shared] [Shared]
public class MainWindowViewModel(AssemblyTreeModel assemblyTreeModel, AnalyzerTreeViewModel analyzerTreeViewModel, SettingsService settingsService, LanguageService languageService) : ObservableObject public class MainWindowViewModel(AssemblyTreeModel assemblyTreeModel, AnalyzerTreeViewModel analyzerTreeViewModel, SettingsService settingsService, LanguageService languageService, DockWorkspace dockWorkspace) : ObservableObject
{ {
public DockWorkspace Workspace => DockWorkspace.Instance; public DockWorkspace Workspace { get; } = dockWorkspace;
public SessionSettings SessionSettings => settingsService.SessionSettings; public SessionSettings SessionSettings => settingsService.SessionSettings;
public LanguageService LanguageService => languageService; public LanguageService LanguageService => languageService;
public AssemblyListManager AssemblyListManager => settingsService.AssemblyListManager; public AssemblyListManager AssemblyListManager => settingsService.AssemblyListManager;
public AnalyzeCommand AnalyzeCommand { get; } = new(assemblyTreeModel, analyzerTreeViewModel); public AnalyzeCommand AnalyzeCommand { get; } = new(assemblyTreeModel, analyzerTreeViewModel);

7
ILSpy/Search/SearchPane.xaml.cs

@ -554,9 +554,12 @@ namespace ICSharpCode.ILSpy.Search
[Shared] [Shared]
sealed class ShowSearchCommand : CommandWrapper sealed class ShowSearchCommand : CommandWrapper
{ {
public ShowSearchCommand() private readonly DockWorkspace dockWorkspace;
public ShowSearchCommand(DockWorkspace dockWorkspace)
: base(NavigationCommands.Search) : base(NavigationCommands.Search)
{ {
this.dockWorkspace = dockWorkspace;
var gestures = NavigationCommands.Search.InputGestures; var gestures = NavigationCommands.Search.InputGestures;
gestures.Clear(); gestures.Clear();
@ -566,7 +569,7 @@ namespace ICSharpCode.ILSpy.Search
protected override void OnExecute(object sender, ExecutedRoutedEventArgs e) protected override void OnExecute(object sender, ExecutedRoutedEventArgs e)
{ {
DockWorkspace.Instance.ShowToolPane(SearchPaneModel.PaneContentId); dockWorkspace.ShowToolPane(SearchPaneModel.PaneContentId);
} }
} }
} }

16
ILSpy/SolutionWriter.cs

@ -47,15 +47,17 @@ namespace ICSharpCode.ILSpy
/// to the <paramref name="solutionFilePath"/>. The directory of this file must either /// to the <paramref name="solutionFilePath"/>. The directory of this file must either
/// be empty or not exist. /// be empty or not exist.
/// </summary> /// </summary>
/// <param name="tabPage"></param>
/// <param name="textView">A reference to the <see cref="DecompilerTextView"/> instance.</param> /// <param name="textView">A reference to the <see cref="DecompilerTextView"/> instance.</param>
/// <param name="solutionFilePath">The target file path of the solution file.</param> /// <param name="solutionFilePath">The target file path of the solution file.</param>
/// <param name="language"></param>
/// <param name="assemblies">The assembly nodes to decompile.</param> /// <param name="assemblies">The assembly nodes to decompile.</param>
///
/// <exception cref="ArgumentException">Thrown when <paramref name="solutionFilePath"/> is null, /// <exception cref="ArgumentException">Thrown when <paramref name="solutionFilePath"/> is null,
/// an empty or a whitespace string.</exception> /// an empty or a whitespace string.</exception>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="textView"/>> or /// <exception cref="ArgumentNullException">Thrown when <paramref name="textView"/>> or
/// <paramref name="assemblies"/> is null.</exception> /// <paramref name="assemblies"/> is null.</exception>
public static void CreateSolution(DecompilerTextView textView, string solutionFilePath, Language language, IEnumerable<LoadedAssembly> assemblies) public static void CreateSolution(TabPageModel tabPage, DecompilerTextView textView, string solutionFilePath,
Language language, IEnumerable<LoadedAssembly> assemblies)
{ {
if (textView == null) if (textView == null)
{ {
@ -75,7 +77,7 @@ namespace ICSharpCode.ILSpy
var writer = new SolutionWriter(solutionFilePath); var writer = new SolutionWriter(solutionFilePath);
textView textView
.RunWithCancellation(ct => writer.CreateSolution(assemblies, language, ct)) .RunWithCancellation(ct => writer.CreateSolution(tabPage, assemblies, language, ct))
.Then(output => textView.ShowText(output)) .Then(output => textView.ShowText(output))
.HandleExceptions(); .HandleExceptions();
} }
@ -93,7 +95,7 @@ namespace ICSharpCode.ILSpy
projects = new ConcurrentBag<ProjectItem>(); projects = new ConcurrentBag<ProjectItem>();
} }
async Task<AvalonEditTextOutput> CreateSolution(IEnumerable<LoadedAssembly> assemblies, Language language, CancellationToken ct) async Task<AvalonEditTextOutput> CreateSolution(TabPageModel tabPage, IEnumerable<LoadedAssembly> assemblies, Language language, CancellationToken ct)
{ {
var result = new AvalonEditTextOutput(); var result = new AvalonEditTextOutput();
@ -113,7 +115,7 @@ namespace ICSharpCode.ILSpy
// long to decompile. // long to decompile.
await Task.Run(() => Parallel.ForEach(Partitioner.Create(assemblies), await Task.Run(() => Parallel.ForEach(Partitioner.Create(assemblies),
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct }, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct },
n => WriteProject(n, language, solutionDirectory, ct))) item => WriteProject(tabPage, item, language, solutionDirectory, ct)))
.ConfigureAwait(false); .ConfigureAwait(false);
if (projects.Count == 0) if (projects.Count == 0)
@ -175,7 +177,7 @@ namespace ICSharpCode.ILSpy
return result; return result;
} }
void WriteProject(LoadedAssembly loadedAssembly, Language language, string targetDirectory, CancellationToken ct) void WriteProject(TabPageModel tabPage, LoadedAssembly loadedAssembly, Language language, string targetDirectory, CancellationToken ct)
{ {
targetDirectory = Path.Combine(targetDirectory, loadedAssembly.ShortName); targetDirectory = Path.Combine(targetDirectory, loadedAssembly.ShortName);
@ -214,7 +216,7 @@ namespace ICSharpCode.ILSpy
using (var projectFileWriter = new StreamWriter(projectFileName)) using (var projectFileWriter = new StreamWriter(projectFileName))
{ {
var projectFileOutput = new PlainTextOutput(projectFileWriter); var projectFileOutput = new PlainTextOutput(projectFileWriter);
var options = DockWorkspace.Instance.ActiveTabPage.CreateDecompilationOptions(); var options = tabPage.CreateDecompilationOptions();
options.FullDecompilation = true; options.FullDecompilation = true;
options.CancellationToken = ct; options.CancellationToken = ct;
options.SaveAsProjectDirectory = targetDirectory; options.SaveAsProjectDirectory = targetDirectory;

3
ILSpy/TaskHelper.cs

@ -20,6 +20,7 @@ using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
@ -200,7 +201,7 @@ namespace ICSharpCode.ILSpy
task.Catch<Exception>(exception => App.Current.Dispatcher.BeginInvoke(new Action(delegate { task.Catch<Exception>(exception => App.Current.Dispatcher.BeginInvoke(new Action(delegate {
AvalonEditTextOutput output = new(); AvalonEditTextOutput output = new();
output.Write(exception.ToString()); output.Write(exception.ToString());
Docking.DockWorkspace.Instance.ShowText(output); App.ExportProvider.GetExportedValue<DockWorkspace>().ShowText(output);
}))).IgnoreExceptions(); }))).IgnoreExceptions();
} }
} }

2
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -547,7 +547,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
dlg.Filter = language.Name + " project|*" + language.ProjectFileExtension + "|" + language.Name + " single file|*" + language.FileExtension + "|All files|*.*"; dlg.Filter = language.Name + " project|*" + language.ProjectFileExtension + "|" + language.Name + " single file|*" + language.FileExtension + "|All files|*.*";
if (dlg.ShowDialog() == true) if (dlg.ShowDialog() == true)
{ {
var options = DockWorkspace.Instance.ActiveTabPage.CreateDecompilationOptions(); var options = DockWorkspace.ActiveTabPage.CreateDecompilationOptions();
options.FullDecompilation = true; options.FullDecompilation = true;
if (dlg.FilterIndex == 1) if (dlg.FilterIndex == 1)
{ {

3
ILSpy/TreeNodes/ILSpyTreeNode.cs

@ -27,6 +27,7 @@ using System.Windows.Threading;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.AssemblyTree; using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpyX.Abstractions; using ICSharpCode.ILSpyX.Abstractions;
using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions; using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions;
using ICSharpCode.ILSpyX.TreeView; using ICSharpCode.ILSpyX.TreeView;
@ -57,6 +58,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
public static LanguageService LanguageService { get; } = App.ExportProvider.GetExportedValue<LanguageService>(); public static LanguageService LanguageService { get; } = App.ExportProvider.GetExportedValue<LanguageService>();
public static DockWorkspace DockWorkspace { get; } = App.ExportProvider.GetExportedValue<DockWorkspace>();
public virtual FilterResult Filter(LanguageSettings settings) public virtual FilterResult Filter(LanguageSettings settings)
{ {
if (string.IsNullOrEmpty(settings.SearchTerm)) if (string.IsNullOrEmpty(settings.SearchTerm))

2
ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs

@ -74,7 +74,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
ISmartTextOutput smartOutput = output as ISmartTextOutput; ISmartTextOutput smartOutput = output as ISmartTextOutput;
if (smartOutput != null) if (smartOutput != null)
{ {
smartOutput.AddButton(Images.Save, Resources.Save, delegate { Save(Docking.DockWorkspace.Instance.ActiveTabPage); }); smartOutput.AddButton(Images.Save, Resources.Save, delegate { Save(DockWorkspace.ActiveTabPage); });
output.WriteLine(); output.WriteLine();
} }
} }

2
ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs

@ -176,7 +176,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
{ {
EnsureLazyChildren(); EnsureLazyChildren();
base.Decompile(language, output, options); base.Decompile(language, output, options);
var textView = (DecompilerTextView)Docking.DockWorkspace.Instance.ActiveTabPage.Content; var textView = (DecompilerTextView)DockWorkspace.ActiveTabPage.Content;
if (stringTableEntries.Count != 0) if (stringTableEntries.Count != 0)
{ {
ISmartTextOutput smartOutput = output as ISmartTextOutput; ISmartTextOutput smartOutput = output as ISmartTextOutput;

18
ILSpy/Util/MenuService.cs

@ -38,10 +38,8 @@ namespace ICSharpCode.ILSpy.Util
{ {
[Export] [Export]
[Shared] [Shared]
public class MenuService(IExportProvider exportProvider) public class MenuService(IExportProvider exportProvider, DockWorkspace dockWorkspace)
{ {
private readonly DockWorkspace dockWorkspace = DockWorkspace.Instance;
public void Init(Menu mainMenu, ToolBar toolBar, InputBindingCollection inputBindings) public void Init(Menu mainMenu, ToolBar toolBar, InputBindingCollection inputBindings)
{ {
InitMainMenu(mainMenu); InitMainMenu(mainMenu);
@ -144,7 +142,7 @@ namespace ICSharpCode.ILSpy.Util
windowMenuItem.Items.Clear(); windowMenuItem.Items.Clear();
var toolItems = dockWorkspace.ToolPanes.Select(toolPane => CreateMenuItem(toolPane, inputBindings)).ToArray(); var toolItems = dockWorkspace.ToolPanes.Select(toolPane => CreateMenuItem(toolPane, inputBindings)).ToArray();
var tabItems = dockWorkspace.TabPages.ObservableSelect(tabPage => CreateMenuItem(tabPage, dockWorkspace)); var tabItems = dockWorkspace.TabPages.ObservableSelect(tabPage => CreateMenuItem(tabPage));
var allItems = new ObservableCompositeCollection<Control>(defaultItems, [new Separator()], toolItems, [new Separator()], tabItems); var allItems = new ObservableCompositeCollection<Control>(defaultItems, [new Separator()], toolItems, [new Separator()], tabItems);
@ -188,7 +186,7 @@ namespace ICSharpCode.ILSpy.Util
} }
static Control CreateMenuItem(TabPageModel pane, DockWorkspace dock) Control CreateMenuItem(TabPageModel pane)
{ {
var header = new TextBlock { var header = new TextBlock {
MaxWidth = 200, MaxWidth = 200,
@ -200,13 +198,13 @@ namespace ICSharpCode.ILSpy.Util
}); });
MenuItem menuItem = new() { MenuItem menuItem = new() {
Command = new TabPageCommand(pane), Command = new TabPageCommand(pane, dockWorkspace),
Header = header, Header = header,
IsCheckable = true IsCheckable = true
}; };
menuItem.SetBinding(MenuItem.IsCheckedProperty, new Binding(nameof(dock.ActiveTabPage)) { menuItem.SetBinding(MenuItem.IsCheckedProperty, new Binding(nameof(dockWorkspace.ActiveTabPage)) {
Source = dock, Source = dockWorkspace,
ConverterParameter = pane, ConverterParameter = pane,
Converter = BinaryOperationConverter.Equality, Converter = BinaryOperationConverter.Equality,
Mode = BindingMode.OneWay Mode = BindingMode.OneWay
@ -215,10 +213,10 @@ namespace ICSharpCode.ILSpy.Util
return menuItem; return menuItem;
} }
static Control CreateMenuItem(ToolPaneModel pane, InputBindingCollection inputBindings) Control CreateMenuItem(ToolPaneModel pane, InputBindingCollection inputBindings)
{ {
MenuItem menuItem = new() { MenuItem menuItem = new() {
Command = pane.AssociatedCommand ?? new ToolPaneCommand(pane.ContentId), Command = pane.AssociatedCommand ?? new ToolPaneCommand(pane.ContentId, dockWorkspace),
Header = pane.Title Header = pane.Title
}; };
var shortcutKey = pane.ShortcutKey; var shortcutKey = pane.ShortcutKey;

5
ILSpy/ViewModels/PaneModel.cs

@ -22,6 +22,7 @@ using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.IL;
using ICSharpCode.ILSpy.Docking;
using TomsToolbox.Wpf; using TomsToolbox.Wpf;
@ -31,6 +32,8 @@ namespace ICSharpCode.ILSpy.ViewModels
{ {
private Throttle titleChangeThrottle; private Throttle titleChangeThrottle;
public static DockWorkspace DockWorkspace => App.ExportProvider.GetExportedValue<DockWorkspace>();
protected PaneModel() protected PaneModel()
{ {
titleChangeThrottle = new Throttle(() => OnPropertyChanged(nameof(Title))); titleChangeThrottle = new Throttle(() => OnPropertyChanged(nameof(Title)));
@ -63,7 +66,7 @@ namespace ICSharpCode.ILSpy.ViewModels
public void Execute(object parameter) public void Execute(object parameter)
{ {
Docking.DockWorkspace.Instance.Remove(model); DockWorkspace.Remove(model);
} }
} }

8
ILSpy/Views/DebugSteps.xaml.cs

@ -22,6 +22,7 @@ namespace ICSharpCode.ILSpy
private readonly AssemblyTreeModel assemblyTreeModel; private readonly AssemblyTreeModel assemblyTreeModel;
private readonly SettingsService settingsService; private readonly SettingsService settingsService;
private readonly LanguageService languageService; private readonly LanguageService languageService;
private readonly DockWorkspace dockWorkspace;
static readonly ILAstWritingOptions writingOptions = new ILAstWritingOptions { static readonly ILAstWritingOptions writingOptions = new ILAstWritingOptions {
UseFieldSugar = true, UseFieldSugar = true,
@ -33,11 +34,12 @@ namespace ICSharpCode.ILSpy
#if DEBUG #if DEBUG
ILAstLanguage language; ILAstLanguage language;
#endif #endif
public DebugSteps(AssemblyTreeModel assemblyTreeModel, SettingsService settingsService, LanguageService languageService) public DebugSteps(AssemblyTreeModel assemblyTreeModel, SettingsService settingsService, LanguageService languageService, DockWorkspace dockWorkspace)
{ {
this.assemblyTreeModel = assemblyTreeModel; this.assemblyTreeModel = assemblyTreeModel;
this.settingsService = settingsService; this.settingsService = settingsService;
this.languageService = languageService; this.languageService = languageService;
this.dockWorkspace = dockWorkspace;
InitializeComponent(); InitializeComponent();
@ -132,8 +134,8 @@ namespace ICSharpCode.ILSpy
void DecompileAsync(int step, bool isDebug = false) void DecompileAsync(int step, bool isDebug = false)
{ {
lastSelectedStep = step; lastSelectedStep = step;
var state = DockWorkspace.Instance.ActiveTabPage.GetState(); var state = dockWorkspace.ActiveTabPage.GetState();
DockWorkspace.Instance.ActiveTabPage.ShowTextViewAsync(textView => textView.DecompileAsync(assemblyTreeModel.CurrentLanguage, assemblyTreeModel.SelectedNodes, dockWorkspace.ActiveTabPage.ShowTextViewAsync(textView => textView.DecompileAsync(assemblyTreeModel.CurrentLanguage, assemblyTreeModel.SelectedNodes,
new DecompilationOptions(assemblyTreeModel.CurrentLanguageVersion, settingsService.DecompilerSettings, settingsService.DisplaySettings) { new DecompilationOptions(assemblyTreeModel.CurrentLanguageVersion, settingsService.DecompilerSettings, settingsService.DisplaySettings) {
StepLimit = step, StepLimit = step,
IsDebug = isDebug, IsDebug = isDebug,

Loading…
Cancel
Save