diff --git a/ICSharpCode.Decompiler/FlowAnalysis/ControlStructureDetector.cs b/ICSharpCode.Decompiler/FlowAnalysis/ControlStructureDetector.cs
index 23a15ab32..d46d1519b 100644
--- a/ICSharpCode.Decompiler/FlowAnalysis/ControlStructureDetector.cs
+++ b/ICSharpCode.Decompiler/FlowAnalysis/ControlStructureDetector.cs
@@ -123,6 +123,9 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
// This algorithm is applied recursively for any substructures (both detected loops and exception blocks)
+ // But maybe we should get rid of this complex stuff and instead treat every backward jump as a loop?
+ // That should still work with the IL produced by compilers, and has the advantage that the detected loop bodies are consecutive IL regions.
+
static void DetectLoops(ControlFlowGraph g, ControlStructure current, CancellationToken cancellationToken)
{
g.ResetVisited();
diff --git a/ILSpy/AssemblyList.cs b/ILSpy/AssemblyList.cs
index 73e8c9c10..39323e92c 100644
--- a/ILSpy/AssemblyList.cs
+++ b/ILSpy/AssemblyList.cs
@@ -30,7 +30,7 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpy
{
///
- /// Describes a list of assemblies.
+ /// A list of assemblies.
///
class AssemblyList
{
@@ -57,6 +57,13 @@ namespace ICSharpCode.ILSpy
Assemblies.Select(asm => new XElement("Assembly", asm.FileName))
);
}
+
+ public bool Dirty { get; set; }
+ public string ListName { get; set; }
+
+ public readonly ObservableCollection Assemblies = new ObservableCollection();
+
+ ConcurrentDictionary typeDict = new ConcurrentDictionary();
void Assemblies_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
@@ -73,13 +80,6 @@ namespace ICSharpCode.ILSpy
);
}
- public bool Dirty { get; set; }
- public string ListName { get; set; }
-
- public readonly ObservableCollection Assemblies = new ObservableCollection();
-
- ConcurrentDictionary typeDict = new ConcurrentDictionary();
-
public void RegisterTypeNode(TypeTreeNode node)
{
// called on background loading thread, so we need to use a ConcurrentDictionary
diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj
index e9603f4fa..b966307e5 100644
--- a/ILSpy/ILSpy.csproj
+++ b/ILSpy/ILSpy.csproj
@@ -202,5 +202,8 @@
+
+
+
\ No newline at end of file
diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs
index 74dae1621..b91412822 100644
--- a/ILSpy/MainWindow.xaml.cs
+++ b/ILSpy/MainWindow.xaml.cs
@@ -40,6 +40,7 @@ namespace ICSharpCode.ILSpy
///
public partial class MainWindow : Window
{
+ ILSpySettings spySettings;
SessionSettings sessionSettings;
AssemblyListManager assemblyListManager;
AssemblyList assemblyList;
@@ -47,10 +48,9 @@ namespace ICSharpCode.ILSpy
public MainWindow()
{
- ILSpySettings spySettings = ILSpySettings.Load();
+ spySettings = ILSpySettings.Load();
this.sessionSettings = new SessionSettings(spySettings);
this.assemblyListManager = new AssemblyListManager(spySettings);
- this.assemblyList = assemblyListManager.LoadList(spySettings, sessionSettings.ActiveAssemblyList);
this.DataContext = sessionSettings;
this.Left = sessionSettings.WindowBounds.Left;
@@ -63,11 +63,25 @@ namespace ICSharpCode.ILSpy
InitializeComponent();
decompilerTextView.mainWindow = this;
+ sessionSettings.FilterSettings.PropertyChanged += filterSettings_PropertyChanged;
+
+ #if DEBUG
+ AddDebugItemsToToolbar();
+ #endif
+ this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
+ }
+
+ void MainWindow_Loaded(object sender, RoutedEventArgs e)
+ {
+ // Load AssemblyList only in Loaded event so that WPF is initialized before we start the CPU-heavy stuff.
+ // This makes the UI come up a bit faster.
+ this.assemblyList = assemblyListManager.LoadList(this.spySettings, sessionSettings.ActiveAssemblyList);
+ this.spySettings = null;
+
assemblyListTreeNode = new AssemblyListTreeNode(assemblyList);
assemblyListTreeNode.FilterSettings = sessionSettings.FilterSettings.Clone();
- sessionSettings.FilterSettings.PropertyChanged += new PropertyChangedEventHandler(filterSettings_PropertyChanged);
- treeView.Root = assemblyListTreeNode;
assemblyListTreeNode.Select = SelectNode;
+ treeView.Root = assemblyListTreeNode;
string[] args = Environment.GetCommandLineArgs();
for (int i = 1; i < args.Length; i++) {
@@ -77,10 +91,6 @@ namespace ICSharpCode.ILSpy
LoadInitialAssemblies();
SelectNode(FindNodeByPath(sessionSettings.ActiveTreeViewPath));
-
- #if DEBUG
- AddDebugItemsToToolbar();
- #endif
}
void LoadInitialAssemblies()
@@ -109,7 +119,8 @@ namespace ICSharpCode.ILSpy
// filterSettings is mutable; but the ILSpyTreeNode filtering assumes that filter settings are immutable.
// Thus, the main window will use one mutable instance (for data-binding), and assign a new clone to the ILSpyTreeNodes whenever the main
// mutable instance changes.
- assemblyListTreeNode.FilterSettings = sessionSettings.FilterSettings.Clone();
+ if (assemblyListTreeNode != null)
+ assemblyListTreeNode.FilterSettings = sessionSettings.FilterSettings.Clone();
if (e.PropertyName == "Language") {
TreeView_SelectionChanged(null, null);
}
diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs
index 8fdff7138..5907898b8 100644
--- a/ILSpy/TextView/DecompilerTextView.cs
+++ b/ILSpy/TextView/DecompilerTextView.cs
@@ -120,10 +120,20 @@ namespace ICSharpCode.ILSpy.TextView
static Task RunDecompiler(ILSpy.Language language, ILSpyTreeNodeBase[] nodes, DecompilationOptions options)
{
+ if (nodes.Length == 0) {
+ // If there's nothing to be decompiled, don't bother starting up a thread.
+ // (Improves perf in some cases since we don't have to wait for the thread-pool to accept our task)
+ TaskCompletionSource tcs = new TaskCompletionSource();
+ tcs.SetResult(new SmartTextOutput());
+ return tcs.Task;
+ }
+
return Task.Factory.StartNew(
delegate {
SmartTextOutput textOutput = new SmartTextOutput();
+ bool first = true;
foreach (var node in nodes) {
+ if (first) first = false; else textOutput.WriteLine();
options.CancellationToken.ThrowIfCancellationRequested();
node.Decompile(language, textOutput, options);
}
diff --git a/ILSpy/TreeNodes/ILSpyTreeNode.cs b/ILSpy/TreeNodes/ILSpyTreeNode.cs
index 4514f44f6..824306c09 100644
--- a/ILSpy/TreeNodes/ILSpyTreeNode.cs
+++ b/ILSpy/TreeNodes/ILSpyTreeNode.cs
@@ -118,6 +118,13 @@ namespace ICSharpCode.ILSpy.TreeNodes
} else {
goto default;
}
+ case NotifyCollectionChangedAction.Remove:
+ if (e.OldItems.Count == 1) {
+ visibleChildren.Remove((T)e.OldItems[0]);
+ break;
+ } else {
+ goto default;
+ }
default:
ResetChildren();
break;