Browse Source

Merge pull request #1801 from icsharpcode/avalondock

Second iteration of docking UI for ILSpy
pull/1820/head
Siegfried Pammer 6 years ago committed by GitHub
parent
commit
7e3441300d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      .gitmodules
  2. 1
      AvalonDock
  3. 10
      BuildTools/update-assemblyinfo.ps1
  4. 6
      ILSpy.sln
  5. 7
      ILSpy/AboutPage.cs
  6. 16
      ILSpy/Analyzers/AnalyzeCommand.cs
  7. 21
      ILSpy/Analyzers/AnalyzerTreeView.cs
  8. 2
      ILSpy/App.xaml.cs
  9. 8
      ILSpy/Commands/DecompileAllCommand.cs
  10. 35
      ILSpy/Commands/DecompileInNewViewCommand.cs
  11. 4
      ILSpy/Commands/DisassembleAllCommand.cs
  12. 4
      ILSpy/Commands/GeneratePdbContextMenuEntry.cs
  13. 4
      ILSpy/Commands/Pdb2XmlCommand.cs
  14. 2
      ILSpy/Commands/SaveCodeContextMenuEntry.cs
  15. 4
      ILSpy/Commands/ShowDebugSteps.cs
  16. 28
      ILSpy/ContextMenuEntry.cs
  17. 10
      ILSpy/DebugSteps.xaml.cs
  18. 43
      ILSpy/Docking/ActiveDocumentConverter.cs
  19. 22
      ILSpy/Docking/DockLayoutSettings.cs
  20. 116
      ILSpy/Docking/DockWorkspace.cs
  21. 32
      ILSpy/Docking/DockingHelper.cs
  22. 143
      ILSpy/Docking/LayoutUpdateStrategy.cs
  23. 61
      ILSpy/Docking/PaneCollection.cs
  24. 22
      ILSpy/Docking/PanePosition.cs
  25. 41
      ILSpy/Docking/PaneStyleSelector.cs
  26. 43
      ILSpy/Docking/PaneTemplateSelector.cs
  27. 16
      ILSpy/ILSpy.csproj
  28. 5
      ILSpy/ISmartTextOutput.cs
  29. 156
      ILSpy/MainWindow.xaml
  30. 102
      ILSpy/MainWindow.xaml.cs
  31. 18
      ILSpy/Properties/Resources.Designer.cs
  32. 6
      ILSpy/Properties/Resources.resx
  33. 3
      ILSpy/Properties/Resources.zh-Hans.resx
  34. 17
      ILSpy/Search/SearchPane.cs
  35. 2
      ILSpy/TaskHelper.cs
  36. 2
      ILSpy/TextView/AvalonEditTextOutput.cs
  37. 19
      ILSpy/TextView/DecompilerTextView.cs
  38. 3
      ILSpy/TextView/DecompilerTextView.xaml
  39. 2
      ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs
  40. 35
      ILSpy/ViewModels/AnalyzerPaneModel.cs
  41. 38
      ILSpy/ViewModels/AssemblyListPaneModel.cs
  42. 35
      ILSpy/ViewModels/DebugStepsPaneModel.cs
  43. 80
      ILSpy/ViewModels/DocumentModel.cs
  44. 140
      ILSpy/ViewModels/PaneModel.cs
  45. 36
      ILSpy/ViewModels/SearchPaneModel.cs
  46. 25
      ILSpy/ViewModels/ToolPaneModel.cs

3
.gitmodules vendored

@ -2,3 +2,6 @@ @@ -2,3 +2,6 @@
path = ILSpy-tests
url = https://github.com/icsharpcode/ILSpy-tests
[submodule "AvalonDock"]
path = AvalonDock
url = https://github.com/siegfriedpammer/AvalonDock

1
AvalonDock

@ -0,0 +1 @@ @@ -0,0 +1 @@
Subproject commit e5ec95d624d5c3e6998832c4d8adefdaf11fd9c8

10
BuildTools/update-assemblyinfo.ps1

@ -38,22 +38,26 @@ function Find-Git() { @@ -38,22 +38,26 @@ function Find-Git() {
return $false;
}
function No-Git() {
return -not (((Test-Dir ".git") -or (Test-File ".git")) -and (Find-Git));
}
function gitVersion() {
if (-not ((Test-Dir ".git") -and (Find-Git))) {
if (No-Git) {
return 0;
}
return [Int32]::Parse((git rev-list --count "$baseCommit..HEAD")) + $baseCommitRev;
}
function gitCommitHash() {
if (-not ((Test-Dir ".git") -and (Find-Git))) {
if (No-Git) {
return "0000000000000000000000000000000000000000";
}
return (git rev-list "$baseCommit..HEAD") | Select -First 1;
}
function gitBranch() {
if (-not ((Test-Dir ".git" -or Test-File ".git") -and (Find-Git))) {
if (No-Git) {
return "no-branch";
}

6
ILSpy.sln

@ -33,6 +33,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICSharpCode.Decompiler.PdbP @@ -33,6 +33,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICSharpCode.Decompiler.PdbP
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILSpy.Tests", "ILSpy.Tests\ILSpy.Tests.csproj", "{B51C6636-B8D1-4200-9869-08F2689DE6C2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xceed.Wpf.AvalonDock", "AvalonDock\source\Components\Xceed.Wpf.AvalonDock\Xceed.Wpf.AvalonDock.csproj", "{D87D783A-A8EE-4A36-AAED-3AB21DC98046}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -79,6 +81,10 @@ Global @@ -79,6 +81,10 @@ Global
{B51C6636-B8D1-4200-9869-08F2689DE6C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B51C6636-B8D1-4200-9869-08F2689DE6C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B51C6636-B8D1-4200-9869-08F2689DE6C2}.Release|Any CPU.Build.0 = Release|Any CPU
{D87D783A-A8EE-4A36-AAED-3AB21DC98046}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D87D783A-A8EE-4A36-AAED-3AB21DC98046}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D87D783A-A8EE-4A36-AAED-3AB21DC98046}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D87D783A-A8EE-4A36-AAED-3AB21DC98046}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

7
ILSpy/AboutPage.cs

@ -41,13 +41,10 @@ namespace ICSharpCode.ILSpy @@ -41,13 +41,10 @@ namespace ICSharpCode.ILSpy
[ExportMainMenuCommand(Menu = nameof(Resources._Help), Header = nameof(Resources._About), MenuOrder = 99999)]
sealed class AboutPage : SimpleCommand
{
[Import]
DecompilerTextView decompilerTextView = null;
public override void Execute(object parameter)
{
MainWindow.Instance.UnselectAll();
Display(decompilerTextView);
Display(Docking.DockWorkspace.Instance.GetTextView());
}
static readonly Uri UpdateUrl = new Uri("https://ilspy.net/updates.xml");
@ -57,7 +54,7 @@ namespace ICSharpCode.ILSpy @@ -57,7 +54,7 @@ namespace ICSharpCode.ILSpy
public static void Display(DecompilerTextView textView)
{
AvalonEditTextOutput output = new AvalonEditTextOutput() { EnableHyperlinks = true };
AvalonEditTextOutput output = new AvalonEditTextOutput() { Title = Resources.About, EnableHyperlinks = true };
output.WriteLine(Resources.ILSpyVersion + RevisionClass.FullVersion);
if(WindowsVersionHelper.HasPackageIdentity) {
output.WriteLine($"Package Name: {WindowsVersionHelper.GetPackageFamilyName()}");

16
ILSpy/Analyzers/AnalyzeCommand.cs

@ -58,17 +58,17 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -58,17 +58,17 @@ namespace ICSharpCode.ILSpy.Analyzers
{
if (context.SelectedTreeNodes != null) {
foreach (IMemberTreeNode node in context.SelectedTreeNodes) {
AnalyzerTreeView.Instance.Analyze(node.Member);
MainWindow.Instance.AnalyzerTreeView.Analyze(node.Member);
}
} else if (context.Reference != null && context.Reference.Reference is IEntity entity) {
AnalyzerTreeView.Instance.Analyze(entity);
MainWindow.Instance.AnalyzerTreeView.Analyze(entity);
}
}
public override bool CanExecute(object parameter)
{
if (AnalyzerTreeView.Instance.IsKeyboardFocusWithin) {
return AnalyzerTreeView.Instance.SelectedItems.OfType<object>().All(n => n is IMemberTreeNode);
if (MainWindow.Instance.AnalyzerTreeView.IsKeyboardFocusWithin) {
return MainWindow.Instance.AnalyzerTreeView.SelectedItems.OfType<object>().All(n => n is IMemberTreeNode);
} else {
return MainWindow.Instance.SelectedNodes.All(n => n is IMemberTreeNode);
}
@ -76,13 +76,13 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -76,13 +76,13 @@ namespace ICSharpCode.ILSpy.Analyzers
public override void Execute(object parameter)
{
if (AnalyzerTreeView.Instance.IsKeyboardFocusWithin) {
foreach (IMemberTreeNode node in AnalyzerTreeView.Instance.SelectedItems.OfType<IMemberTreeNode>().ToArray()) {
AnalyzerTreeView.Instance.Analyze(node.Member);
if (MainWindow.Instance.AnalyzerTreeView.IsKeyboardFocusWithin) {
foreach (IMemberTreeNode node in MainWindow.Instance.AnalyzerTreeView.SelectedItems.OfType<IMemberTreeNode>().ToArray()) {
MainWindow.Instance.AnalyzerTreeView.Analyze(node.Member);
}
} else {
foreach (IMemberTreeNode node in MainWindow.Instance.SelectedNodes) {
AnalyzerTreeView.Instance.Analyze(node.Member);
MainWindow.Instance.AnalyzerTreeView.Analyze(node.Member);
}
}
}

21
ILSpy/Analyzers/AnalyzerTreeView.cs

@ -23,6 +23,8 @@ using System.Linq; @@ -23,6 +23,8 @@ using System.Linq;
using System.Windows;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.Analyzers.TreeNodes;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.TreeView;
namespace ICSharpCode.ILSpy.Analyzers
@ -32,21 +34,7 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -32,21 +34,7 @@ namespace ICSharpCode.ILSpy.Analyzers
/// </summary>
public class AnalyzerTreeView : SharpTreeView, IPane
{
static AnalyzerTreeView instance;
public static AnalyzerTreeView Instance
{
get
{
if (instance == null) {
App.Current.VerifyAccess();
instance = new AnalyzerTreeView();
}
return instance;
}
}
private AnalyzerTreeView()
public AnalyzerTreeView()
{
this.ShowRoot = false;
this.Root = new AnalyzerRootNode { Language = MainWindow.Instance.CurrentLanguage };
@ -72,8 +60,7 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -72,8 +60,7 @@ namespace ICSharpCode.ILSpy.Analyzers
public void Show()
{
if (!IsVisible)
MainWindow.Instance.ShowInNewPane("Analyzer", this, PanePosition.Bottom);
DockWorkspace.Instance.ToolPanes.Add(AnalyzerPaneModel.Instance);
}
public void Show(AnalyzerTreeNode node)

2
ILSpy/App.xaml.cs

@ -244,7 +244,7 @@ namespace ICSharpCode.ILSpy @@ -244,7 +244,7 @@ namespace ICSharpCode.ILSpy
}
}
}
ILSpy.MainWindow.Instance.TextView.ShowText(output);
Docking.DockWorkspace.Instance.ShowText(output);
e.Handled = true;
}
}

8
ILSpy/Commands/DecompileAllCommand.cs

@ -38,7 +38,7 @@ namespace ICSharpCode.ILSpy @@ -38,7 +38,7 @@ namespace ICSharpCode.ILSpy
public override void Execute(object parameter)
{
MainWindow.Instance.TextView.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
AvalonEditTextOutput output = new AvalonEditTextOutput();
Parallel.ForEach(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct }, delegate(LoadedAssembly asm) {
if (!asm.HasLoadError) {
@ -64,7 +64,7 @@ namespace ICSharpCode.ILSpy @@ -64,7 +64,7 @@ namespace ICSharpCode.ILSpy
}
});
return output;
}, ct)).Then(output => MainWindow.Instance.TextView.ShowText(output)).HandleExceptions();
}, ct)).Then(output => Docking.DockWorkspace.Instance.ShowText(output)).HandleExceptions();
}
}
@ -77,7 +77,7 @@ namespace ICSharpCode.ILSpy @@ -77,7 +77,7 @@ namespace ICSharpCode.ILSpy
var language = MainWindow.Instance.CurrentLanguage;
var nodes = MainWindow.Instance.SelectedNodes.ToArray();
var options = new DecompilationOptions();
MainWindow.Instance.TextView.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
options.CancellationToken = ct;
Stopwatch w = Stopwatch.StartNew();
for (int i = 0; i < numRuns; ++i) {
@ -90,7 +90,7 @@ namespace ICSharpCode.ILSpy @@ -90,7 +90,7 @@ namespace ICSharpCode.ILSpy
double msPerRun = w.Elapsed.TotalMilliseconds / numRuns;
output.Write($"Average time: {msPerRun.ToString("f1")}ms\n");
return output;
}, ct)).Then(output => MainWindow.Instance.TextView.ShowText(output)).HandleExceptions();
}, ct)).Then(output => Docking.DockWorkspace.Instance.ShowText(output)).HandleExceptions();
}
}
}

35
ILSpy/Commands/DecompileInNewViewCommand.cs

@ -16,37 +16,50 @@ @@ -16,37 +16,50 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes;
namespace ICSharpCode.ILSpy.Commands
{
// [ExportContextMenuEntry(Header = nameof(Resources.DecompileToNewPanel), Icon = "images/Search", Category = nameof(Resources.Analyze), Order = 90)]
[ExportContextMenuEntry(Header = nameof(Resources.DecompileToNewPanel), Icon = "images/Search", Category = nameof(Resources.Analyze), Order = 90)]
internal sealed class DecompileInNewViewCommand : IContextMenuEntry
{
public bool IsVisible(TextViewContext context)
{
if (context.SelectedTreeNodes == null)
return false;
return true;
return context.SelectedTreeNodes != null || context.Reference?.Reference is IEntity;
}
public bool IsEnabled(TextViewContext context)
{
if (context.SelectedTreeNodes == null)
return false;
return true;
return context.SelectedTreeNodes != null || context.Reference?.Reference is IEntity;
}
public async void Execute(TextViewContext context)
public void Execute(TextViewContext context)
{
var dtv = new DecompilerTextView();
if (context.SelectedTreeNodes != null) {
var nodes = context.SelectedTreeNodes.Cast<ILSpyTreeNode>().ToArray();
DecompileNodes(nodes);
} else if (context.Reference?.Reference is IEntity entity) {
var node = MainWindow.Instance.FindTreeNode(entity);
if (node != null) {
DecompileNodes(node);
}
}
}
private static void DecompileNodes(params ILSpyTreeNode[] nodes)
{
var title = string.Join(", ", nodes.Select(x => x.ToString()));
MainWindow.Instance.ShowInNewPane(title, dtv, PanePosition.Document);
await dtv.DecompileAsync(MainWindow.Instance.CurrentLanguage, nodes, new DecompilationOptions());
DockWorkspace.Instance.Documents.Add(new ViewModels.DecompiledDocumentModel(title, title) { Language = MainWindow.Instance.CurrentLanguage, LanguageVersion = MainWindow.Instance.CurrentLanguageVersion });
DockWorkspace.Instance.ActiveDocument = DockWorkspace.Instance.Documents.Last();
MainWindow.Instance.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background, (Action)delegate {
DockWorkspace.Instance.GetTextView().DecompileAsync(MainWindow.Instance.CurrentLanguage, nodes, new DecompilationOptions());
});
}
}
}

4
ILSpy/Commands/DisassembleAllCommand.cs

@ -35,7 +35,7 @@ namespace ICSharpCode.ILSpy @@ -35,7 +35,7 @@ namespace ICSharpCode.ILSpy
public override void Execute(object parameter)
{
MainWindow.Instance.TextView.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
AvalonEditTextOutput output = new AvalonEditTextOutput();
Parallel.ForEach(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct }, delegate(LoadedAssembly asm) {
if (!asm.HasLoadError) {
@ -61,7 +61,7 @@ namespace ICSharpCode.ILSpy @@ -61,7 +61,7 @@ namespace ICSharpCode.ILSpy
}
});
return output;
}, ct)).Then(output => MainWindow.Instance.TextView.ShowText(output)).HandleExceptions();
}, ct)).Then(output => Docking.DockWorkspace.Instance.ShowText(output)).HandleExceptions();
}
}
}

4
ILSpy/Commands/GeneratePdbContextMenuEntry.cs

@ -64,7 +64,7 @@ namespace ICSharpCode.ILSpy @@ -64,7 +64,7 @@ namespace ICSharpCode.ILSpy
if (dlg.ShowDialog() != true) return;
DecompilationOptions options = new DecompilationOptions();
string fileName = dlg.FileName;
MainWindow.Instance.TextView.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
AvalonEditTextOutput output = new AvalonEditTextOutput();
Stopwatch stopwatch = Stopwatch.StartNew();
using (FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write)) {
@ -83,7 +83,7 @@ namespace ICSharpCode.ILSpy @@ -83,7 +83,7 @@ namespace ICSharpCode.ILSpy
output.AddButton(null, "Open Explorer", delegate { Process.Start("explorer", "/select,\"" + fileName + "\""); });
output.WriteLine();
return output;
}, ct)).Then(output => MainWindow.Instance.TextView.ShowText(output)).HandleExceptions();
}, ct)).Then(output => Docking.DockWorkspace.Instance.ShowText(output)).HandleExceptions();
}
}

4
ILSpy/Commands/Pdb2XmlCommand.cs

@ -49,7 +49,7 @@ namespace ICSharpCode.ILSpy @@ -49,7 +49,7 @@ namespace ICSharpCode.ILSpy
{
var highlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml");
var options = PdbToXmlOptions.IncludeEmbeddedSources | PdbToXmlOptions.IncludeMethodSpans | PdbToXmlOptions.IncludeTokens;
MainWindow.Instance.TextView.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
AvalonEditTextOutput output = new AvalonEditTextOutput();
var writer = new TextOutputWriter(output);
foreach (var node in nodes) {
@ -60,7 +60,7 @@ namespace ICSharpCode.ILSpy @@ -60,7 +60,7 @@ namespace ICSharpCode.ILSpy
PdbToXmlConverter.ToXml(writer, pdbStream, peStream, options);
}
return output;
}, ct)).Then(output => MainWindow.Instance.TextView.ShowNodes(output, null, highlighting)).HandleExceptions();
}, ct)).Then(output => Docking.DockWorkspace.Instance.ShowNodes(output, null, highlighting)).HandleExceptions();
}
}

2
ILSpy/Commands/SaveCodeContextMenuEntry.cs

@ -55,7 +55,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -55,7 +55,7 @@ namespace ICSharpCode.ILSpy.TextView
public static void Execute(IReadOnlyList<SharpTreeNode> selectedNodes)
{
var currentLanguage = MainWindow.Instance.CurrentLanguage;
var textView = MainWindow.Instance.TextView;
var textView = Docking.DockWorkspace.Instance.GetTextView();
if (selectedNodes.Count == 1 && selectedNodes[0] is ILSpyTreeNode singleSelection) {
// if there's only one treenode selected
// we will invoke the custom Save logic

4
ILSpy/Commands/ShowDebugSteps.cs

@ -1,6 +1,8 @@ @@ -1,6 +1,8 @@
#if DEBUG
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy.Commands
{
@ -9,7 +11,7 @@ namespace ICSharpCode.ILSpy.Commands @@ -9,7 +11,7 @@ namespace ICSharpCode.ILSpy.Commands
{
public override void Execute(object parameter)
{
DebugSteps.Show();
DockWorkspace.Instance.ToolPanes.Add(DebugStepsPaneModel.Instance);
}
}
}

28
ILSpy/ContextMenuEntry.cs

@ -126,20 +126,23 @@ namespace ICSharpCode.ILSpy @@ -126,20 +126,23 @@ namespace ICSharpCode.ILSpy
/// <summary>
/// Enables extensible context menu support for the specified tree view.
/// </summary>
public static void Add(SharpTreeView treeView, DecompilerTextView textView = null)
public static void Add(SharpTreeView treeView)
{
var provider = new ContextMenuProvider(treeView, textView);
var provider = new ContextMenuProvider(treeView);
treeView.ContextMenuOpening += provider.treeView_ContextMenuOpening;
// Context menu is shown only when the ContextMenu property is not null before the
// ContextMenuOpening event handler is called.
treeView.ContextMenu = new ContextMenu();
if (textView != null) {
}
public static void Add(DecompilerTextView textView)
{
var provider = new ContextMenuProvider(textView);
textView.ContextMenuOpening += provider.textView_ContextMenuOpening;
// Context menu is shown only when the ContextMenu property is not null before the
// ContextMenuOpening event handler is called.
textView.ContextMenu = new ContextMenu();
}
}
public static void Add(ListBox listBox)
{
@ -158,15 +161,22 @@ namespace ICSharpCode.ILSpy @@ -158,15 +161,22 @@ namespace ICSharpCode.ILSpy
entries = App.ExportProvider.GetExports<IContextMenuEntry, IContextMenuEntryMetadata>().ToArray();
}
ContextMenuProvider(SharpTreeView treeView, DecompilerTextView textView = null) : this()
ContextMenuProvider(DecompilerTextView textView)
: this()
{
this.textView = textView ?? throw new ArgumentNullException(nameof(textView));
}
ContextMenuProvider(SharpTreeView treeView)
: this()
{
this.treeView = treeView;
this.textView = textView;
this.treeView = treeView ?? throw new ArgumentNullException(nameof(treeView));
}
ContextMenuProvider(ListBox listBox) : this()
ContextMenuProvider(ListBox listBox)
: this()
{
this.listBox = listBox;
this.listBox = listBox ?? throw new ArgumentNullException(nameof(listBox));
}
void treeView_ContextMenuOpening(object sender, ContextMenuEventArgs e)

10
ILSpy/DebugSteps.xaml.cs

@ -4,6 +4,8 @@ using System.Windows.Controls; @@ -4,6 +4,8 @@ using System.Windows.Controls;
using System.Windows.Input;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy
{
@ -20,7 +22,7 @@ namespace ICSharpCode.ILSpy @@ -20,7 +22,7 @@ namespace ICSharpCode.ILSpy
ILAstLanguage language;
#endif
DebugSteps()
public DebugSteps()
{
InitializeComponent();
@ -79,7 +81,7 @@ namespace ICSharpCode.ILSpy @@ -79,7 +81,7 @@ namespace ICSharpCode.ILSpy
public static void Show()
{
MainWindow.Instance.ShowInNewPane(Properties.Resources.DebugSteps, new DebugSteps(), PanePosition.Top);
DockWorkspace.Instance.ToolPanes.Add(DebugStepsPaneModel.Instance);
}
void IPane.Closed()
@ -121,8 +123,8 @@ namespace ICSharpCode.ILSpy @@ -121,8 +123,8 @@ namespace ICSharpCode.ILSpy
{
lastSelectedStep = step;
var window = MainWindow.Instance;
var state = window.TextView.GetState();
window.TextView.DecompileAsync(window.CurrentLanguage, window.SelectedNodes,
var state = DockWorkspace.Instance.GetState();
DockWorkspace.Instance.GetTextView().DecompileAsync(window.CurrentLanguage, window.SelectedNodes,
new DecompilationOptions(window.CurrentLanguageVersion) {
StepLimit = step,
IsDebug = isDebug,

43
ILSpy/Docking/ActiveDocumentConverter.cs

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
// Copyright (c) 2019 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows.Data;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy.Docking
{
public class ActiveDocumentConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is DocumentModel)
return value;
return Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is DocumentModel)
return value;
return Binding.DoNothing;
}
}
}

22
ILSpy/Docking/DockLayoutSettings.cs

@ -1,4 +1,22 @@ @@ -1,4 +1,22 @@
using System;
// Copyright (c) 2019 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.IO;
using System.Linq;
using System.Xml;
@ -32,7 +50,7 @@ namespace ICSharpCode.ILSpy.Docking @@ -32,7 +50,7 @@ namespace ICSharpCode.ILSpy.Docking
public void Deserialize(XmlLayoutSerializer serializer)
{
if (!Valid)
return;
rawSettings = "<LayoutRoot />";
using (StringReader reader = new StringReader(rawSettings)) {
serializer.Deserialize(reader);

116
ILSpy/Docking/DockWorkspace.cs

@ -0,0 +1,116 @@ @@ -0,0 +1,116 @@
// Copyright (c) 2019 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy.Docking
{
public class DockWorkspace : INotifyPropertyChanged
{
private SessionSettings sessionSettings;
public event PropertyChangedEventHandler PropertyChanged;
public static DockWorkspace Instance { get; } = new DockWorkspace();
private DockWorkspace()
{
}
public PaneCollection<DocumentModel> Documents { get; } = new PaneCollection<DocumentModel>();
public PaneCollection<ToolPaneModel> ToolPanes { get; } = new PaneCollection<ToolPaneModel>();
public void Remove(PaneModel model)
{
Documents.Remove(model as DocumentModel);
ToolPanes.Remove(model as ToolPaneModel);
}
private DocumentModel _activeDocument = null;
public DocumentModel ActiveDocument {
get {
return _activeDocument;
}
set {
if (_activeDocument != value) {
_activeDocument = value;
if (value is DecompiledDocumentModel ddm) {
this.sessionSettings.FilterSettings.Language = ddm.Language;
this.sessionSettings.FilterSettings.LanguageVersion = ddm.LanguageVersion;
}
RaisePropertyChanged(nameof(ActiveDocument));
}
}
}
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void ShowText(AvalonEditTextOutput textOutput)
{
GetTextView().ShowText(textOutput);
}
public DecompilerTextView GetTextView()
{
return ((DecompiledDocumentModel)ActiveDocument).TextView;
}
public DecompilerTextViewState GetState()
{
return GetTextView().GetState();
}
public Task<T> RunWithCancellation<T>(Func<CancellationToken, Task<T>> taskCreation)
{
return GetTextView().RunWithCancellation(taskCreation);
}
internal void ShowNodes(AvalonEditTextOutput output, TreeNodes.ILSpyTreeNode[] nodes, IHighlightingDefinition highlighting)
{
GetTextView().ShowNodes(output, nodes, highlighting);
}
internal void LoadSettings(SessionSettings sessionSettings)
{
this.sessionSettings = sessionSettings;
sessionSettings.FilterSettings.PropertyChanged += FilterSettings_PropertyChanged;
}
private void FilterSettings_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (ActiveDocument is DecompiledDocumentModel ddm) {
if (e.PropertyName == "Language" || e.PropertyName == "LanguageVersion") {
ddm.Language = sessionSettings.FilterSettings.Language;
ddm.LanguageVersion = sessionSettings.FilterSettings.LanguageVersion;
}
}
}
}
}

32
ILSpy/Docking/DockingHelper.cs

@ -1,32 +0,0 @@ @@ -1,32 +0,0 @@
using System.Windows;
using System.Windows.Controls;
using Xceed.Wpf.AvalonDock.Layout;
namespace ICSharpCode.ILSpy.Docking
{
public static class DockingHelper
{
public static void DockHorizontal(LayoutContent layoutContent, ILayoutElement paneRelativeTo, GridLength dockHeight, bool dockBefore = false)
{
if (paneRelativeTo is ILayoutDocumentPane parentDocumentPane) {
var parentDocumentGroup = paneRelativeTo.FindParent<LayoutDocumentPaneGroup>();
if (parentDocumentGroup == null) {
var grandParent = parentDocumentPane.Parent as ILayoutContainer;
parentDocumentGroup = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Vertical };
grandParent.ReplaceChild(paneRelativeTo, parentDocumentGroup);
parentDocumentGroup.Children.Add(parentDocumentPane);
}
parentDocumentGroup.Orientation = System.Windows.Controls.Orientation.Vertical;
int indexOfParentPane = parentDocumentGroup.IndexOfChild(parentDocumentPane);
var layoutDocumentPane = new LayoutDocumentPane(layoutContent) { DockHeight = dockHeight };
parentDocumentGroup.InsertChildAt(dockBefore ? indexOfParentPane : indexOfParentPane + 1, layoutDocumentPane);
layoutContent.IsActive = true;
layoutContent.Root.CollectGarbage();
Application.Current.MainWindow.Dispatcher.Invoke(() => {
layoutDocumentPane.DockHeight = dockHeight;
}, System.Windows.Threading.DispatcherPriority.Loaded);
}
}
}
}

143
ILSpy/Docking/LayoutUpdateStrategy.cs

@ -0,0 +1,143 @@ @@ -0,0 +1,143 @@
// Copyright (c) 2019 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using ICSharpCode.ILSpy.ViewModels;
using Xceed.Wpf.AvalonDock.Layout;
namespace ICSharpCode.ILSpy.Docking
{
public class LayoutUpdateStrategy : ILayoutUpdateStrategy
{
public bool BeforeInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableToShow, ILayoutContainer destinationContainer)
{
if (destinationContainer?.FindParent<LayoutFloatingWindow>() != null)
return false;
PanePosition targetPosition = anchorableToShow.Content is PaneModel model ? model.DefaultPosition : PanePosition.Document;
switch (targetPosition) {
case PanePosition.Top:
case PanePosition.Bottom:
case PanePosition.Left:
case PanePosition.Right:
var pane = GetOrCreatePane(layout, targetPosition.ToString());
if (pane == null)
return false;
anchorableToShow.CanDockAsTabbedDocument = false;
pane.Children.Add(anchorableToShow);
return true;
case PanePosition.Document:
var documentPane = GetOrCreateDocumentPane(layout);
if (documentPane == null)
return false;
documentPane.Children.Add(anchorableToShow);
return true;
default:
throw new NotSupportedException($"Enum value {targetPosition} is not supported");
}
}
private LayoutAnchorablePane GetOrCreatePane(LayoutRoot layout, string name)
{
var pane = layout.Descendents().OfType<LayoutAnchorablePane>().FirstOrDefault(p => p.Name == name + "Pane");
if (pane != null)
return pane;
var layoutPanel = layout.Children.OfType<LayoutPanel>().FirstOrDefault();
if (layoutPanel == null) {
layout.RootPanel = new LayoutPanel() { Orientation = Orientation.Horizontal };
}
if (layoutPanel.Orientation != Orientation.Horizontal) {
layoutPanel.Orientation = Orientation.Horizontal;
}
LayoutAnchorablePane result = null;
switch (name) {
case "Top":
case "Bottom":
var centerLayoutPanel = layoutPanel.Children.OfType<LayoutPanel>().FirstOrDefault();
if (centerLayoutPanel == null) {
layoutPanel.Children.Insert(0, centerLayoutPanel = new LayoutPanel() { Orientation = Orientation.Vertical });
}
if (centerLayoutPanel.Orientation != Orientation.Vertical) {
centerLayoutPanel.Orientation = Orientation.Vertical;
}
if (name == "Top")
centerLayoutPanel.Children.Insert(0, result = new LayoutAnchorablePane { Name = name + "Pane", DockMinHeight = 250 });
else
centerLayoutPanel.Children.Add(result = new LayoutAnchorablePane { Name = name + "Pane", DockMinHeight = 250 });
return result;
case "Left":
case "Right":
if (name == "Left")
layoutPanel.Children.Insert(0, result = new LayoutAnchorablePane { Name = name + "Pane", DockMinWidth = 250 });
else
layoutPanel.Children.Add(result = new LayoutAnchorablePane { Name = name + "Pane", DockMinWidth = 250 });
return result;
default:
throw new NotImplementedException();
}
}
public void AfterInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableShown)
{
}
public bool BeforeInsertDocument(LayoutRoot layout, LayoutDocument anchorableToShow, ILayoutContainer destinationContainer)
{
if (destinationContainer?.FindParent<LayoutFloatingWindow>() != null)
return false;
var documentPane = GetOrCreateDocumentPane(layout);
if (documentPane == null)
return false;
documentPane.Children.Add(anchorableToShow);
return true;
}
private LayoutDocumentPane GetOrCreateDocumentPane(LayoutRoot layout)
{
var pane = layout.Descendents().OfType<LayoutDocumentPane>().FirstOrDefault();
if (pane != null)
return pane;
var layoutPanel = layout.Children.OfType<LayoutPanel>().FirstOrDefault();
if (layoutPanel == null) {
layout.RootPanel = new LayoutPanel() { Orientation = Orientation.Horizontal };
}
if (layoutPanel.Orientation != Orientation.Horizontal) {
layoutPanel.Orientation = Orientation.Horizontal;
}
var centerLayoutPanel = layoutPanel.Children.OfType<LayoutPanel>().FirstOrDefault();
if (centerLayoutPanel == null) {
layoutPanel.Children.Insert(0, centerLayoutPanel = new LayoutPanel() { Orientation = Orientation.Vertical });
}
if (centerLayoutPanel.Orientation != Orientation.Vertical) {
centerLayoutPanel.Orientation = Orientation.Vertical;
}
LayoutDocumentPane result;
centerLayoutPanel.Children.Add(result = new LayoutDocumentPane());
return result;
}
public void AfterInsertDocument(LayoutRoot layout, LayoutDocument anchorableShown)
{
}
}
}

61
ILSpy/Docking/PaneCollection.cs

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
// Copyright (c) 2019 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy.Docking
{
public class PaneCollection<T> : INotifyCollectionChanged, INotifyPropertyChanged, ICollection<T>
where T : PaneModel
{
private ObservableCollection<T> observableCollection = new ObservableCollection<T>();
public event NotifyCollectionChangedEventHandler CollectionChanged;
public event PropertyChangedEventHandler PropertyChanged;
public PaneCollection()
{
observableCollection.CollectionChanged += (sender, e) => CollectionChanged?.Invoke(this, e);
}
public void Add(T item)
{
if (!this.Any(pane => pane.ContentId == item.ContentId)) {
observableCollection.Add(item);
}
item.IsVisible = true;
item.IsActive = true;
}
public int Count => observableCollection.Count();
public bool IsReadOnly => false;
public void Clear() => observableCollection.Clear();
public bool Contains(T item) => observableCollection.Contains(item);
public void CopyTo(T[] array, int arrayIndex) => observableCollection.CopyTo(array, arrayIndex);
public bool Remove(T item) => observableCollection.Remove(item);
public IEnumerator<T> GetEnumerator() => observableCollection.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => observableCollection.GetEnumerator();
}
}

22
ILSpy/Docking/PanePosition.cs

@ -1,9 +1,29 @@ @@ -1,9 +1,29 @@
namespace ICSharpCode.ILSpy
// Copyright (c) 2019 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
namespace ICSharpCode.ILSpy
{
public enum PanePosition
{
Top,
Bottom,
Left,
Right,
Document
}
}

41
ILSpy/Docking/PaneStyleSelector.cs

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
using System.Windows;
using System.Windows.Controls;
using ICSharpCode.ILSpy.ViewModels;
// Copyright (c) 2019 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
namespace ICSharpCode.ILSpy.Docking
{
public class PaneStyleSelector : StyleSelector
{
public Style ToolPaneStyle { get; set; }
public Style DocumentStyle { get; set; }
public override Style SelectStyle(object item, DependencyObject container)
{
if (item is DocumentModel)
return DocumentStyle;
if (item is ToolPaneModel)
return ToolPaneStyle;
return base.SelectStyle(item, container);
}
}
}

43
ILSpy/Docking/PaneTemplateSelector.cs

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
// Copyright (c) 2019 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
namespace ICSharpCode.ILSpy.Docking
{
public class TemplateMapping
{
public Type Type { get; set; }
public DataTemplate Template { get; set; }
}
public class PaneTemplateSelector : DataTemplateSelector
{
public Collection<TemplateMapping> Mappings { get; set; } = new Collection<TemplateMapping>();
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
return Mappings.FirstOrDefault(m => m.Type == item.GetType())?.Template
?? base.SelectTemplate(item, container);
}
}
}

16
ILSpy/ILSpy.csproj

@ -50,7 +50,6 @@ @@ -50,7 +50,6 @@
<ItemGroup>
<PackageReference Include="AvalonEdit" Version="6.0.0" />
<PackageReference Include="Dirkster.AvalonDock" Version="3.5.12" />
<PackageReference Include="Microsoft.VisualStudio.Composition" Version="16.3.7" />
<PackageReference Include="System.Composition" Version="1.3.0" />
<PackageReference Include="Mono.Cecil" Version="0.10.3" />
@ -60,6 +59,7 @@ @@ -60,6 +59,7 @@
<ItemGroup>
<ProjectReference Include="..\ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj" />
<ProjectReference Include="..\SharpTreeView\ICSharpCode.TreeView.csproj" />
<ProjectReference Include="..\AvalonDock\source\Components\Xceed.Wpf.AvalonDock\Xceed.Wpf.AvalonDock.csproj" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
@ -139,8 +139,19 @@ @@ -139,8 +139,19 @@
<Compile Include="DebugSteps.xaml.cs">
<DependentUpon>DebugSteps.xaml</DependentUpon>
</Compile>
<Compile Include="Docking\DockingHelper.cs" />
<Compile Include="Docking\ActiveDocumentConverter.cs" />
<Compile Include="ViewModels\AssemblyListPaneModel.cs" />
<Compile Include="Docking\DockLayoutSettings.cs" />
<Compile Include="ViewModels\DocumentModel.cs" />
<Compile Include="Docking\LayoutUpdateStrategy.cs" />
<Compile Include="Docking\PaneCollection.cs" />
<Compile Include="ViewModels\PaneModel.cs" />
<Compile Include="Docking\PaneStyleSelector.cs" />
<Compile Include="Docking\PaneTemplateSelector.cs" />
<Compile Include="ViewModels\DebugStepsPaneModel.cs" />
<Compile Include="ViewModels\AnalyzerPaneModel.cs" />
<Compile Include="ViewModels\SearchPaneModel.cs" />
<Compile Include="ViewModels\ToolPaneModel.cs" />
<Compile Include="ILSpyTraceListener.cs" />
<Compile Include="DecompilationOptions.cs" />
<Compile Include="ExtensionMethods.cs" />
@ -253,6 +264,7 @@ @@ -253,6 +264,7 @@
<Compile Include="TreeNodes\ResourceNodes\XmlResourceNode.cs" />
<Compile Include="TreeNodes\SearchMsdnContextMenuEntry.cs" />
<Compile Include="Analyzers\Builtin\TypeExtensionMethodsAnalyzer.cs" />
<Compile Include="Docking\DockWorkspace.cs" />
<EmbeddedResource Include="..\doc\LGPL.txt">
<Link>LGPL.txt</Link>
</EmbeddedResource>

5
ILSpy/ISmartTextOutput.cs

@ -38,6 +38,11 @@ namespace ICSharpCode.ILSpy @@ -38,6 +38,11 @@ namespace ICSharpCode.ILSpy
void BeginSpan(HighlightingColor highlightingColor);
void EndSpan();
/// <summary>
/// Gets/sets the title displayed in the document tab's header.
/// </summary>
string Title { get; set; }
}
public static class SmartTextOutputExtensions

156
ILSpy/MainWindow.xaml

@ -6,7 +6,12 @@ @@ -6,7 +6,12 @@
xmlns:local="clr-namespace:ICSharpCode.ILSpy"
xmlns:avalondock="http://schemas.xceed.com/wpf/xaml/avalondock"
xmlns:controls="clr-namespace:ICSharpCode.ILSpy.Controls"
xmlns:avalondockproperties="clr-namespace:Xceed.Wpf.AvalonDock.Properties;assembly=Xceed.Wpf.AvalonDock"
xmlns:docking="clr-namespace:ICSharpCode.ILSpy.Docking"
xmlns:textview="clr-namespace:ICSharpCode.ILSpy.TextView"
xmlns:analyzers="clr-namespace:ICSharpCode.ILSpy.Analyzers"
xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties"
xmlns:viewmodels="clr-namespace:ICSharpCode.ILSpy.ViewModels"
Title="ILSpy"
MinWidth="250"
MinHeight="200"
@ -18,7 +23,46 @@ @@ -18,7 +23,46 @@
>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<docking:ActiveDocumentConverter x:Key="ActiveDocumentConverter"/>
<avalondock:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<tv:SharpTreeView x:Key="TreeView"
AutomationProperties.Name="Assemblies and Classes"
SelectionChanged="TreeView_SelectionChanged"
ShowRoot="False"
AllowDropOrder="True"
AllowDrop="True"
BorderThickness="0,1,1,1" Visibility="Visible" />
<DataTemplate x:Key="AssemblyListPaneTemplate">
<ContentControl Content="{StaticResource TreeView}" />
</DataTemplate>
<local:DebugSteps x:Key="DebugSteps" />
<DataTemplate x:Key="DebugStepsPaneTemplate">
<ContentControl Content="{StaticResource DebugSteps}" />
</DataTemplate>
<local:SearchPane x:Key="SearchPane" />
<DataTemplate x:Key="SearchPaneTemplate">
<ContentControl Content="{StaticResource SearchPane}" />
</DataTemplate>
<analyzers:AnalyzerTreeView x:Key="AnalyzerTreeView" />
<DataTemplate x:Key="AnalyzerPaneTemplate">
<ContentControl Content="{StaticResource AnalyzerTreeView}" />
</DataTemplate>
<ContentPresenter x:Key="MainPane" />
<DataTemplate x:Key="DecompilerTextViewTemplate">
<textview:DecompilerTextView DataContext="{Binding}" />
</DataTemplate>
</Window.Resources>
<Window.CommandBindings>
<CommandBinding
Command="Open"
@ -54,9 +98,9 @@ @@ -54,9 +98,9 @@
<MenuItem Header="{x:Static properties:Resources._File}" />
<!-- contents of file menu are added using MEF -->
<MenuItem Header="{x:Static properties:Resources._View}">
<MenuItem Header="{x:Static properties:Resources.Show_publiconlyTypesMembers}" IsCheckable="True" IsChecked="{Binding FilterSettings.ApiVisPublicOnly}" />
<MenuItem Header="{x:Static properties:Resources.Show_internalTypesMembers}" IsCheckable="True" IsChecked="{Binding FilterSettings.ApiVisPublicAndInternal}" />
<MenuItem Header="{x:Static properties:Resources.Show_allTypesAndMembers}" IsCheckable="True" IsChecked="{Binding FilterSettings.ApiVisAll}" />
<MenuItem Header="{x:Static properties:Resources.Show_publiconlyTypesMembers}" IsCheckable="True" IsChecked="{Binding SessionSettings.FilterSettings.ApiVisPublicOnly}" />
<MenuItem Header="{x:Static properties:Resources.Show_internalTypesMembers}" IsCheckable="True" IsChecked="{Binding SessionSettings.FilterSettings.ApiVisPublicAndInternal}" />
<MenuItem Header="{x:Static properties:Resources.Show_allTypesAndMembers}" IsCheckable="True" IsChecked="{Binding SessionSettings.FilterSettings.ApiVisAll}" />
</MenuItem>
</Menu>
<!-- ToolBar -->
@ -79,23 +123,23 @@ @@ -79,23 +123,23 @@
<Separator />
<!-- 'Open' toolbar category is inserted here -->
<Separator />
<CheckBox IsChecked="{Binding FilterSettings.ApiVisPublicOnly}" ToolTip="{x:Static properties:Resources.ShowPublicOnlyTypesMembers}">
<CheckBox IsChecked="{Binding SessionSettings.FilterSettings.ApiVisPublicOnly}" ToolTip="{x:Static properties:Resources.ShowPublicOnlyTypesMembers}">
<Image Width="16" Height="16" Source="{controls:XamlResource Images/ShowPublicOnly}" />
</CheckBox>
<CheckBox IsChecked="{Binding FilterSettings.ApiVisPublicAndInternal}" ToolTip="{x:Static properties:Resources.ShowInternalTypesMembers}">
<CheckBox IsChecked="{Binding SessionSettings.FilterSettings.ApiVisPublicAndInternal}" ToolTip="{x:Static properties:Resources.ShowInternalTypesMembers}">
<Image Width="16" Height="16" Source="{controls:XamlResource Images/ShowPrivateInternal}" />
</CheckBox>
<CheckBox IsChecked="{Binding FilterSettings.ApiVisAll}" ToolTip="{x:Static properties:Resources.ShowAllTypesAndMembers}">
<CheckBox IsChecked="{Binding SessionSettings.FilterSettings.ApiVisAll}" ToolTip="{x:Static properties:Resources.ShowAllTypesAndMembers}">
<Image Width="16" Height="16" Source="{controls:XamlResource Images/ShowAll}" />
</CheckBox>
<Separator />
<ComboBox Name="languageComboBox" DisplayMemberPath="Name" Width="100" MaxDropDownHeight="Auto"
ItemsSource="{x:Static local:Languages.AllLanguages}" ToolTip="{x:Static properties:Resources.SelectLanguageDropdownTooltip}"
SelectedItem="{Binding FilterSettings.Language}"/>
SelectedItem="{Binding SessionSettings.FilterSettings.Language}"/>
<ComboBox Name="languageVersionComboBox" DisplayMemberPath="DisplayName" Width="120" MaxDropDownHeight="Auto" ToolTip="{x:Static properties:Resources.SelectVersionDropdownTooltip}"
Visibility="{Binding SelectedItem.HasLanguageVersions, ElementName=languageComboBox, Converter={StaticResource BooleanToVisibilityConverter}}"
ItemsSource="{Binding SelectedItem.LanguageVersions, ElementName=languageComboBox, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding FilterSettings.LanguageVersion, UpdateSourceTrigger=PropertyChanged}"/>
SelectedItem="{Binding SessionSettings.FilterSettings.LanguageVersion, UpdateSourceTrigger=PropertyChanged}"/>
</ToolBar>
<Border DockPanel.Dock="Top" BorderBrush="Black" BorderThickness="1" Name="updatePanel" Visibility="Collapsed">
<DockPanel KeyboardNavigation.TabNavigation="Contained">
@ -116,41 +160,79 @@ @@ -116,41 +160,79 @@
Text="{x:Static properties:Resources.StandBy}"/>
</StatusBarItem>
</StatusBar>
<!-- Main grid separating left pane (treeView) from main pane (textEditor) -->
<avalondock:DockingManager x:Name="DockManager"
AllowMixedOrientation="True" Grid.ColumnSpan="2">
<avalondock:LayoutRoot x:Name="LayoutRoot" >
<avalondock:LayoutPanel Orientation="Vertical">
DataContext="{Binding Workspace}"
AnchorablesSource="{Binding ToolPanes}"
DocumentsSource="{Binding Documents}"
ActiveContent="{Binding ActiveDocument, Mode=TwoWay, Converter={StaticResource ActiveDocumentConverter}}"
AllowMixedOrientation="True">
<avalondock:LayoutRoot>
<avalondock:LayoutPanel Orientation="Horizontal">
<avalondock:LayoutAnchorablePaneGroup DockWidth="400" Orientation="Vertical">
<avalondock:LayoutAnchorablePane DockHeight="*">
<avalondock:LayoutAnchorable x:Name="Tree" Title="Assemblies" CanHide="False" CanClose="False">
<!-- Left pane: Tree View of assemblies and classes -->
<tv:SharpTreeView
Name="treeView"
AutomationProperties.Name="Assemblies and Classes"
SelectionChanged="TreeView_SelectionChanged"
ShowRoot="False"
AllowDropOrder="True"
AllowDrop="True"
BorderThickness="0,1,1,1" Visibility="Visible" />
</avalondock:LayoutAnchorable>
</avalondock:LayoutAnchorablePane>
</avalondock:LayoutAnchorablePaneGroup>
<avalondock:LayoutDocumentPaneGroup DockWidth="*">
<avalondock:LayoutDocumentPane x:Name="adDocumentPane">
<avalondock:LayoutDocument Title="View" CanClose="False">
<!-- decompilerTextView is into the mainPane by code -->
<ContentPresenter Name="mainPane" />
</avalondock:LayoutDocument>
</avalondock:LayoutDocumentPane>
</avalondock:LayoutDocumentPaneGroup>
<avalondock:LayoutAnchorablePane DockMinWidth="150" Name="LeftPane" />
<avalondock:LayoutPanel Orientation="Vertical">
<avalondock:LayoutAnchorablePane DockMinHeight="150" Name="TopPane" />
<avalondock:LayoutDocumentPane />
<avalondock:LayoutAnchorablePane DockMinHeight="150" Name="BottomPane" />
</avalondock:LayoutPanel>
<avalondock:LayoutAnchorablePane DockMinWidth="150" Name="RightPane" />
</avalondock:LayoutPanel>
</avalondock:LayoutRoot>
<avalondock:DockingManager.DocumentHeaderTemplate>
<DataTemplate>
<TextBlock x:Name="headerText" Text="{Binding Title}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsActive}" Value="True">
<Setter TargetName="headerText" Property="FontWeight" Value="Bold" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</avalondock:DockingManager.DocumentHeaderTemplate>
<avalondock:DockingManager.LayoutUpdateStrategy>
<docking:LayoutUpdateStrategy />
</avalondock:DockingManager.LayoutUpdateStrategy>
<avalondock:DockingManager.LayoutItemTemplateSelector>
<docking:PaneTemplateSelector>
<docking:PaneTemplateSelector.Mappings>
<docking:TemplateMapping Type="{x:Type viewmodels:AssemblyListPaneModel}" Template="{StaticResource AssemblyListPaneTemplate}" />
<docking:TemplateMapping Type="{x:Type viewmodels:SearchPaneModel}" Template="{StaticResource SearchPaneTemplate}" />
<docking:TemplateMapping Type="{x:Type viewmodels:DebugStepsPaneModel}" Template="{StaticResource DebugStepsPaneTemplate}" />
<docking:TemplateMapping Type="{x:Type viewmodels:AnalyzerPaneModel}" Template="{StaticResource AnalyzerPaneTemplate}" />
<docking:TemplateMapping Type="{x:Type viewmodels:DecompiledDocumentModel}" Template="{StaticResource DecompilerTextViewTemplate}" />
</docking:PaneTemplateSelector.Mappings>
</docking:PaneTemplateSelector>
</avalondock:DockingManager.LayoutItemTemplateSelector>
<avalondock:DockingManager.LayoutItemContainerStyleSelector>
<docking:PaneStyleSelector>
<docking:PaneStyleSelector.ToolPaneStyle>
<Style TargetType="{x:Type avalondock:LayoutAnchorableItem}">
<Setter Property="Title" Value="{Binding Model.Title}"/>
<Setter Property="Visibility" Value="{Binding Model.IsVisible, Mode=TwoWay, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter={x:Static Visibility.Hidden}}"/>
<Setter Property="ContentId" Value="{Binding Model.ContentId}"/>
<Setter Property="IsSelected" Value="{Binding Model.IsSelected, Mode=TwoWay}"/>
<Setter Property="IsActive" Value="{Binding Model.IsActive, Mode=TwoWay}"/>
<Setter Property="CanHide" Value="{Binding Model.IsCloseable}" />
<Setter Property="HideCommand" Value="{Binding Model.CloseCommand}" />
<Setter Property="CanClose" Value="{Binding Model.IsCloseable}" />
</Style>
</docking:PaneStyleSelector.ToolPaneStyle>
<docking:PaneStyleSelector.DocumentStyle>
<Style TargetType="{x:Type avalondock:LayoutItem}">
<Setter Property="Title" Value="{Binding Model.Title}"/>
<Setter Property="Visibility" Value="{Binding Model.IsVisible, Mode=TwoWay, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter={x:Static Visibility.Hidden}}"/>
<Setter Property="ContentId" Value="{Binding Model.ContentId}"/>
<Setter Property="IsSelected" Value="{Binding Model.IsSelected, Mode=TwoWay}"/>
<Setter Property="IsActive" Value="{Binding Model.IsActive, Mode=TwoWay}"/>
<Setter Property="CloseCommand" Value="{Binding Model.CloseCommand}" />
<Setter Property="CanClose" Value="{Binding Model.IsCloseable}" />
</Style>
</docking:PaneStyleSelector.DocumentStyle>
</docking:PaneStyleSelector>
</avalondock:DockingManager.LayoutItemContainerStyleSelector>
</avalondock:DockingManager>
</DockPanel>
</Window>

102
ILSpy/MainWindow.xaml.cs

@ -38,9 +38,12 @@ using ICSharpCode.Decompiler.Documentation; @@ -38,9 +38,12 @@ using ICSharpCode.Decompiler.Documentation;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.ILSpy.Analyzers;
using ICSharpCode.ILSpy.Controls;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.TreeView;
using Microsoft.Win32;
using OSVersionHelper;
@ -49,6 +52,12 @@ using Xceed.Wpf.AvalonDock.Layout.Serialization; @@ -49,6 +52,12 @@ using Xceed.Wpf.AvalonDock.Layout.Serialization;
namespace ICSharpCode.ILSpy
{
class MainWindowDataContext
{
public DockWorkspace Workspace { get; set; }
public SessionSettings SessionSettings { get; set; }
}
/// <summary>
/// The main window of the application.
/// </summary>
@ -64,8 +73,6 @@ namespace ICSharpCode.ILSpy @@ -64,8 +73,6 @@ namespace ICSharpCode.ILSpy
AssemblyList assemblyList;
AssemblyListTreeNode assemblyListTreeNode;
readonly DecompilerTextView decompilerTextView;
static MainWindow instance;
public static MainWindow Instance {
@ -76,6 +83,30 @@ namespace ICSharpCode.ILSpy @@ -76,6 +83,30 @@ namespace ICSharpCode.ILSpy
get { return sessionSettings; }
}
public ContentPresenter mainPane {
get {
return FindResource("MainPane") as ContentPresenter;
}
}
public SharpTreeView treeView {
get {
return FindResource("TreeView") as SharpTreeView;
}
}
public AnalyzerTreeView AnalyzerTreeView {
get {
return FindResource("AnalyzerTreeView") as AnalyzerTreeView;
}
}
public SearchPane SearchPane {
get {
return FindResource("SearchPane") as SearchPane;
}
}
public MainWindow()
{
instance = this;
@ -86,11 +117,14 @@ namespace ICSharpCode.ILSpy @@ -86,11 +117,14 @@ namespace ICSharpCode.ILSpy
this.Icon = new BitmapImage(new Uri("pack://application:,,,/ILSpy;component/images/ILSpy.ico"));
this.DataContext = sessionSettings;
this.DataContext = new MainWindowDataContext {
Workspace = DockWorkspace.Instance,
SessionSettings = sessionSettings
};
DockWorkspace.Instance.LoadSettings(sessionSettings);
InitializeComponent();
decompilerTextView = App.ExportProvider.GetExportedValue<DecompilerTextView>();
mainPane.Content = decompilerTextView;
sessionSettings.DockLayout.Deserialize(new XmlLayoutSerializer(DockManager));
@ -98,7 +132,7 @@ namespace ICSharpCode.ILSpy @@ -98,7 +132,7 @@ namespace ICSharpCode.ILSpy
InitMainMenu();
InitToolbar();
ContextMenuProvider.Add(treeView, decompilerTextView);
ContextMenuProvider.Add(treeView);
this.Loaded += MainWindow_Loaded;
}
@ -295,8 +329,8 @@ namespace ICSharpCode.ILSpy @@ -295,8 +329,8 @@ namespace ICSharpCode.ILSpy
commandLineLoadedAssemblies.Clear(); // clear references once we don't need them anymore
NavigateOnLaunch(args.NavigateTo, sessionSettings.ActiveTreeViewPath, spySettings, relevantAssemblies);
if (args.Search != null) {
SearchPane.Instance.SearchTerm = args.Search;
SearchPane.Instance.Show();
SearchPane.SearchTerm = args.Search;
SearchPane.Show();
}
}
@ -339,7 +373,7 @@ namespace ICSharpCode.ILSpy @@ -339,7 +373,7 @@ namespace ICSharpCode.ILSpy
if (!found && treeView.SelectedItem == initialSelection) {
AvalonEditTextOutput output = new AvalonEditTextOutput();
output.Write(string.Format("Cannot find '{0}' in command line specified assemblies.", navigateTo));
decompilerTextView.ShowText(output);
DockWorkspace.Instance.ShowText(output);
}
} else if (relevantAssemblies.Count == 1) {
// NavigateTo == null and an assembly was given on the command-line:
@ -367,7 +401,7 @@ namespace ICSharpCode.ILSpy @@ -367,7 +401,7 @@ namespace ICSharpCode.ILSpy
// only if not showing the about page, perform the update check:
await ShowMessageIfUpdatesAvailableAsync(spySettings);
} else {
AboutPage.Display(decompilerTextView);
AboutPage.Display(DockWorkspace.Instance.GetTextView());
}
}
}
@ -428,6 +462,10 @@ namespace ICSharpCode.ILSpy @@ -428,6 +462,10 @@ namespace ICSharpCode.ILSpy
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
DockWorkspace.Instance.ToolPanes.Add(AssemblyListPaneModel.Instance);
DockWorkspace.Instance.Documents.Add(new DecompiledDocumentModel() { IsCloseable = false, Language = CurrentLanguage, LanguageVersion = CurrentLanguageVersion });
DockWorkspace.Instance.ActiveDocument = DockWorkspace.Instance.Documents.First();
ILSpySettings spySettings = this.spySettingsForMainWindow_Loaded;
this.spySettingsForMainWindow_Loaded = null;
var loadPreviousAssemblies = Options.MiscSettingsPanel.CurrentMiscSettings.LoadPreviousAssemblies;
@ -464,7 +502,7 @@ namespace ICSharpCode.ILSpy @@ -464,7 +502,7 @@ namespace ICSharpCode.ILSpy
AvalonEditTextOutput output = new AvalonEditTextOutput();
if (FormatExceptions(App.StartupExceptions.ToArray(), output))
decompilerTextView.ShowText(output);
DockWorkspace.Instance.ShowText(output);
}
bool FormatExceptions(App.ExceptionData[] exceptions, ITextOutput output)
@ -882,7 +920,7 @@ namespace ICSharpCode.ILSpy @@ -882,7 +920,7 @@ namespace ICSharpCode.ILSpy
void SearchCommandExecuted(object sender, ExecutedRoutedEventArgs e)
{
SearchPane.Instance.Show();
DockWorkspace.Instance.ToolPanes.Add(SearchPaneModel.Instance);
}
#endregion
@ -891,8 +929,7 @@ namespace ICSharpCode.ILSpy @@ -891,8 +929,7 @@ namespace ICSharpCode.ILSpy
{
DecompileSelectedNodes();
if (SelectionChanged != null)
SelectionChanged(sender, e);
SelectionChanged?.Invoke(sender, e);
}
Task decompilationTask;
@ -907,7 +944,7 @@ namespace ICSharpCode.ILSpy @@ -907,7 +944,7 @@ namespace ICSharpCode.ILSpy
return;
if (recordHistory) {
var dtState = decompilerTextView.GetState();
var dtState = DockWorkspace.Instance.GetState();
if (dtState != null)
history.UpdateCurrent(new NavigationState(dtState));
history.Record(new NavigationState(treeView.SelectedItems.OfType<SharpTreeNode>()));
@ -915,10 +952,10 @@ namespace ICSharpCode.ILSpy @@ -915,10 +952,10 @@ namespace ICSharpCode.ILSpy
if (treeView.SelectedItems.Count == 1) {
ILSpyTreeNode node = treeView.SelectedItem as ILSpyTreeNode;
if (node != null && node.View(decompilerTextView))
if (node != null && node.View(DockWorkspace.Instance.GetTextView()))
return;
}
decompilationTask = decompilerTextView.DecompileAsync(this.CurrentLanguage, this.SelectedNodes, new DecompilationOptions() { TextViewState = state });
decompilationTask = DockWorkspace.Instance.GetTextView().DecompileAsync(this.CurrentLanguage, this.SelectedNodes, new DecompilationOptions() { TextViewState = state });
}
void SaveCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
@ -942,10 +979,6 @@ namespace ICSharpCode.ILSpy @@ -942,10 +979,6 @@ namespace ICSharpCode.ILSpy
}
}
public DecompilerTextView TextView {
get { return decompilerTextView; }
}
public Language CurrentLanguage => sessionSettings.FilterSettings.Language;
public LanguageVersion CurrentLanguageVersion => sessionSettings.FilterSettings.LanguageVersion;
@ -989,7 +1022,7 @@ namespace ICSharpCode.ILSpy @@ -989,7 +1022,7 @@ namespace ICSharpCode.ILSpy
void NavigateHistory(bool forward)
{
var dtState = decompilerTextView.GetState();
var dtState = DockWorkspace.Instance.GetState();
if (dtState != null)
history.UpdateCurrent(new NavigationState(dtState));
var newState = forward ? history.GoForward() : history.GoBack();
@ -1042,31 +1075,6 @@ namespace ICSharpCode.ILSpy @@ -1042,31 +1075,6 @@ namespace ICSharpCode.ILSpy
return loadedAssy.FileName;
}
#region Top/Bottom Pane management
public void ShowInNewPane(string title, object content, PanePosition panePosition, string toolTip = null)
{
// Hack to avoid opening the same pane multiple times
var existingPane = DockManager.Layout.Descendents().OfType<LayoutContent>().FirstOrDefault(
a => (a.Title == title) && (a.Content != null));
if (existingPane != null) {
existingPane.IsActive = true;
return;
}
if (panePosition == PanePosition.Document) {
var layoutDocument = new LayoutDocument() { Title = title, Content = content, ToolTip = toolTip, CanClose = true };
var documentPane = this.DockManager.Layout.Descendents().OfType<LayoutDocumentPane>().FirstOrDefault();
documentPane.Children.Add(layoutDocument);
} else {
var layoutAnchorable = new LayoutAnchorable() { Title = title, Content = content, ToolTip = toolTip, CanClose = true, CanHide = true };
var documentPane = this.DockManager.Layout.Descendents().OfType<LayoutDocumentPane>().FirstOrDefault();
Docking.DockingHelper.DockHorizontal(layoutAnchorable, documentPane, new GridLength(200), panePosition == PanePosition.Top);
}
}
#endregion
public void UnselectAll()
{
treeView.UnselectAll();

18
ILSpy/Properties/Resources.Designer.cs generated

@ -267,6 +267,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -267,6 +267,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to About.
/// </summary>
public static string About {
get {
return ResourceManager.GetString("About", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to |All Files|*.*.
/// </summary>
@ -303,6 +312,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -303,6 +312,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Assemblies.
/// </summary>
public static string Assemblies {
get {
return ResourceManager.GetString("Assemblies", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Assembly.
/// </summary>

6
ILSpy/Properties/Resources.resx

@ -775,4 +775,10 @@ Are you sure you want to continue?</value> @@ -775,4 +775,10 @@ Are you sure you want to continue?</value>
<data name="DecompilerSettings.DetectAsyncUsingAndForeachStatements" xml:space="preserve">
<value>Detect awaited using and foreach statements</value>
</data>
<data name="About" xml:space="preserve">
<value>About</value>
</data>
<data name="Assemblies" xml:space="preserve">
<value>Assemblies</value>
</data>
</root>

3
ILSpy/Properties/Resources.zh-Hans.resx

@ -729,4 +729,7 @@ @@ -729,4 +729,7 @@
<data name="SearchMSDN" xml:space="preserve">
<value>搜索MSDN...</value>
</data>
<data name="About" xml:space="preserve">
<value>关于</value>
</data>
</root>

17
ILSpy/Search/SearchPane.cs

@ -31,7 +31,9 @@ using System.Windows.Input; @@ -31,7 +31,9 @@ using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.Search;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy
{
@ -42,7 +44,6 @@ namespace ICSharpCode.ILSpy @@ -42,7 +44,6 @@ namespace ICSharpCode.ILSpy
{
const int MAX_RESULTS = 1000;
const int MAX_REFRESH_TIME_MS = 10; // More means quicker forward of data, less means better responsibility
static SearchPane instance;
RunningSearch currentSearch;
bool runSearchOnNextShow;
@ -53,17 +54,7 @@ namespace ICSharpCode.ILSpy @@ -53,17 +54,7 @@ namespace ICSharpCode.ILSpy
get { return (ObservableCollection<SearchResult>)GetValue(ResultsProperty); }
}
public static SearchPane Instance {
get {
if (instance == null) {
App.Current.VerifyAccess();
instance = new SearchPane();
}
return instance;
}
}
private SearchPane()
public SearchPane()
{
InitializeComponent();
searchModeComboBox.Items.Add(new { Image = Images.Library, Name = "Types and Members" });
@ -114,7 +105,7 @@ namespace ICSharpCode.ILSpy @@ -114,7 +105,7 @@ namespace ICSharpCode.ILSpy
public void Show()
{
if (!IsVisible) {
MainWindow.Instance.ShowInNewPane(Properties.Resources.SearchPane_Search, this, PanePosition.Top);
DockWorkspace.Instance.ToolPanes.Add(SearchPaneModel.Instance);
if (runSearchOnNextShow) {
runSearchOnNextShow = false;
StartSearch(this.SearchTerm);

2
ILSpy/TaskHelper.cs

@ -196,7 +196,7 @@ namespace ICSharpCode.ILSpy @@ -196,7 +196,7 @@ namespace ICSharpCode.ILSpy
task.Catch<Exception>(exception => MainWindow.Instance.Dispatcher.BeginInvoke(new Action(delegate {
AvalonEditTextOutput output = new AvalonEditTextOutput();
output.Write(exception.ToString());
MainWindow.Instance.TextView.ShowText(output);
Docking.DockWorkspace.Instance.ShowText(output);
}))).IgnoreExceptions();
}
}

2
ILSpy/TextView/AvalonEditTextOutput.cs

@ -82,6 +82,8 @@ namespace ICSharpCode.ILSpy.TextView @@ -82,6 +82,8 @@ namespace ICSharpCode.ILSpy.TextView
public string IndentationString { get; set; } = "\t";
public string Title { get; set; }
internal readonly List<VisualLineElementGenerator> elementGenerators = new List<VisualLineElementGenerator>();
/// <summary>List of all references that were written to the output</summary>

19
ILSpy/TextView/DecompilerTextView.cs

@ -53,6 +53,7 @@ using ICSharpCode.Decompiler.TypeSystem; @@ -53,6 +53,7 @@ using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.AvalonEdit;
using ICSharpCode.ILSpy.Options;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.ViewModels;
using Microsoft.Win32;
namespace ICSharpCode.ILSpy.TextView
@ -61,7 +62,6 @@ namespace ICSharpCode.ILSpy.TextView @@ -61,7 +62,6 @@ namespace ICSharpCode.ILSpy.TextView
/// Manages the TextEditor showing the decompiled code.
/// Contains all the threading logic that makes the decompiler work in the background.
/// </summary>
[Export, PartCreationPolicy(CreationPolicy.Shared)]
public sealed partial class DecompilerTextView : UserControl, IDisposable
{
readonly ReferenceElementGenerator referenceElementGenerator;
@ -140,6 +140,8 @@ namespace ICSharpCode.ILSpy.TextView @@ -140,6 +140,8 @@ namespace ICSharpCode.ILSpy.TextView
// add marker service & margin
textEditor.TextArea.TextView.BackgroundRenderers.Add(textMarkerService);
textEditor.TextArea.TextView.LineTransformers.Add(textMarkerService);
ContextMenuProvider.Add(this);
}
void RemoveEditCommand(RoutedUICommand command)
@ -627,6 +629,10 @@ namespace ICSharpCode.ILSpy.TextView @@ -627,6 +629,10 @@ namespace ICSharpCode.ILSpy.TextView
foldingStrategy.UpdateFoldings(foldingManager, textEditor.Document);
Debug.WriteLine(" Updating folding: {0}", w.Elapsed); w.Restart();
}
if (this.DataContext is PaneModel model) {
model.Title = textOutput.Title;
}
}
#endregion
@ -749,6 +755,9 @@ namespace ICSharpCode.ILSpy.TextView @@ -749,6 +755,9 @@ namespace ICSharpCode.ILSpy.TextView
void DecompileNodes(DecompilationContext context, ITextOutput textOutput)
{
var nodes = context.TreeNodes;
if (textOutput is ISmartTextOutput smartTextOutput) {
smartTextOutput.Title = string.Join(", ", nodes.Select(n => n.ToString()));
}
for (int i = 0; i < nodes.Length; i++) {
if (i > 0)
textOutput.WriteLine();
@ -1032,6 +1041,14 @@ namespace ICSharpCode.ILSpy.TextView @@ -1032,6 +1041,14 @@ namespace ICSharpCode.ILSpy.TextView
}
}
#endregion
private void self_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.OldValue is DecompiledDocumentModel oldModel)
oldModel.TextView = null;
if (e.NewValue is DecompiledDocumentModel newModel)
newModel.TextView = this;
}
}
public class DecompilerTextViewState

3
ILSpy/TextView/DecompilerTextView.xaml

@ -2,7 +2,8 @@ @@ -2,7 +2,8 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties"
xmlns:ae="clr-namespace:ICSharpCode.AvalonEdit;assembly=ICSharpCode.AvalonEdit">
xmlns:ae="clr-namespace:ICSharpCode.AvalonEdit;assembly=ICSharpCode.AvalonEdit"
DataContextChanged="self_DataContextChanged">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="boolToVisibility" />
</UserControl.Resources>

2
ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs

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

35
ILSpy/ViewModels/AnalyzerPaneModel.cs

@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
// Copyright (c) 2019 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
namespace ICSharpCode.ILSpy.ViewModels
{
public class AnalyzerPaneModel : ToolPaneModel
{
public const string PaneContentId = "analyzerPane";
public static AnalyzerPaneModel Instance { get; } = new AnalyzerPaneModel();
public override PanePosition DefaultPosition => PanePosition.Bottom;
private AnalyzerPaneModel()
{
ContentId = PaneContentId;
Title = Properties.Resources.Analyze;
}
}
}

38
ILSpy/ViewModels/AssemblyListPaneModel.cs

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
// Copyright (c) 2019 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using ICSharpCode.ILSpy.Properties;
namespace ICSharpCode.ILSpy.ViewModels
{
public class AssemblyListPaneModel : ToolPaneModel
{
public const string PaneContentId = "assemblyListPane";
public static AssemblyListPaneModel Instance { get; } = new AssemblyListPaneModel();
public override PanePosition DefaultPosition => PanePosition.Left;
private AssemblyListPaneModel()
{
Title = Resources.Assemblies;
ContentId = PaneContentId;
IsCloseable = false;
}
}
}

35
ILSpy/ViewModels/DebugStepsPaneModel.cs

@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
// Copyright (c) 2019 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
namespace ICSharpCode.ILSpy.ViewModels
{
public class DebugStepsPaneModel : ToolPaneModel
{
public const string PaneContentId = "debugStepsPane";
public static DebugStepsPaneModel Instance { get; } = new DebugStepsPaneModel();
public override PanePosition DefaultPosition => PanePosition.Top;
private DebugStepsPaneModel()
{
ContentId = PaneContentId;
Title = Properties.Resources.DebugSteps;
}
}
}

80
ILSpy/ViewModels/DocumentModel.cs

@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
// Copyright (c) 2019 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TextView;
namespace ICSharpCode.ILSpy.ViewModels
{
public abstract class DocumentModel : PaneModel
{
public override PanePosition DefaultPosition => PanePosition.Document;
protected DocumentModel(string contentId, string title)
{
this.ContentId = contentId;
this.Title = title;
}
}
public class DecompiledDocumentModel : DocumentModel
{
public DecompiledDocumentModel()
: base("//Decompiled", Resources.View)
{
}
public DecompiledDocumentModel(string id, string title)
: base("//Decompiled/" + id, title)
{
}
private DecompilerTextView textView;
public DecompilerTextView TextView {
get => textView;
set {
if (textView != value) {
textView = value;
RaisePropertyChanged(nameof(TextView));
}
}
}
private Language language;
public Language Language {
get => language;
set {
if (language != value) {
language = value;
RaisePropertyChanged(nameof(Language));
}
}
}
private LanguageVersion languageVersion;
public LanguageVersion LanguageVersion {
get => languageVersion;
set {
if (languageVersion != value) {
languageVersion = value;
RaisePropertyChanged(nameof(LanguageVersion));
}
}
}
}
}

140
ILSpy/ViewModels/PaneModel.cs

@ -0,0 +1,140 @@ @@ -0,0 +1,140 @@
// Copyright (c) 2019 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.ComponentModel;
using System.Windows.Input;
namespace ICSharpCode.ILSpy.ViewModels
{
public abstract class PaneModel : INotifyPropertyChanged
{
class CloseCommandImpl : ICommand
{
readonly PaneModel model;
public CloseCommandImpl(PaneModel model)
{
this.model = model;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return model.IsCloseable;
}
public void Execute(object parameter)
{
Docking.DockWorkspace.Instance.Remove(model);
}
}
public PaneModel()
{
this.closeCommand = new CloseCommandImpl(this);
}
public abstract PanePosition DefaultPosition { get; }
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private bool isSelected = false;
public bool IsSelected {
get => isSelected;
set {
if (isSelected != value) {
isSelected = value;
RaisePropertyChanged(nameof(IsSelected));
}
}
}
private bool isActive = false;
public bool IsActive {
get => isActive;
set {
if (isActive != value) {
isActive = value;
RaisePropertyChanged(nameof(IsActive));
}
}
}
private bool isVisible = true;
public bool IsVisible {
get { return isVisible; }
set {
if (isVisible != value) {
isVisible = value;
RaisePropertyChanged(nameof(IsVisible));
}
}
}
private bool isCloseable = true;
public bool IsCloseable {
get { return isCloseable; }
set {
if (isCloseable != value) {
isCloseable = value;
RaisePropertyChanged(nameof(IsCloseable));
}
}
}
private ICommand closeCommand;
public ICommand CloseCommand {
get { return closeCommand; }
set {
if (closeCommand != value) {
closeCommand = value;
RaisePropertyChanged(nameof(CloseCommand));
}
}
}
private string contentId;
public string ContentId {
get => contentId;
set {
if (contentId != value) {
contentId = value;
RaisePropertyChanged(nameof(ContentId));
}
}
}
private string title;
public string Title {
get => title;
set {
if (title != value) {
title = value;
RaisePropertyChanged(nameof(Title));
}
}
}
}
}

36
ILSpy/ViewModels/SearchPaneModel.cs

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
// Copyright (c) 2019 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
namespace ICSharpCode.ILSpy.ViewModels
{
public class SearchPaneModel : ToolPaneModel
{
public const string PaneContentId = "searchPane";
public static SearchPaneModel Instance { get; } = new SearchPaneModel();
public override PanePosition DefaultPosition => PanePosition.Top;
private SearchPaneModel()
{
ContentId = PaneContentId;
Title = Properties.Resources.SearchPane_Search;
IsCloseable = true;
}
}
}

25
ILSpy/ViewModels/ToolPaneModel.cs

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
// Copyright (c) 2019 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
namespace ICSharpCode.ILSpy.ViewModels
{
public abstract class ToolPaneModel : PaneModel
{
}
}
Loading…
Cancel
Save