mirror of https://github.com/icsharpcode/ILSpy.git
3 changed files with 125 additions and 27 deletions
@ -0,0 +1,105 @@
@@ -0,0 +1,105 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using System.Windows.Threading; |
||||
using ICSharpCode.Decompiler; |
||||
|
||||
namespace ICSharpCode.ILSpy.TreeNodes |
||||
{ |
||||
/// <summary>
|
||||
/// Node that is lazy-loaded and loads its children on a background thread.
|
||||
/// </summary>
|
||||
abstract class ThreadedTreeNode : ILSpyTreeNode<ILSpyTreeNodeBase> |
||||
{ |
||||
Task<List<ILSpyTreeNodeBase>> loadChildrenTask; |
||||
|
||||
public ThreadedTreeNode() |
||||
{ |
||||
this.LazyLoading = true; |
||||
} |
||||
|
||||
public void Invalidate() |
||||
{ |
||||
this.LazyLoading = true; |
||||
this.Children.Clear(); |
||||
loadChildrenTask = null; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// FetchChildren() runs on the main thread; but the enumerator is consumed on a background thread
|
||||
/// </summary>
|
||||
protected abstract IEnumerable<ILSpyTreeNodeBase> FetchChildren(CancellationToken ct); |
||||
|
||||
protected override sealed void LoadChildren() |
||||
{ |
||||
this.Children.Add(new LoadingTreeNode()); |
||||
|
||||
CancellationToken ct = CancellationToken.None; |
||||
|
||||
var fetchChildrenEnumerable = FetchChildren(ct); |
||||
Task<List<ILSpyTreeNodeBase>> thisTask = null; |
||||
thisTask = new Task<List<ILSpyTreeNodeBase>>( |
||||
delegate { |
||||
List<ILSpyTreeNodeBase> result = new List<ILSpyTreeNodeBase>(); |
||||
foreach (ILSpyTreeNodeBase child in fetchChildrenEnumerable) { |
||||
ct.ThrowIfCancellationRequested(); |
||||
result.Add(child); |
||||
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action<ILSpyTreeNodeBase>( |
||||
delegate (ILSpyTreeNodeBase newChild) { |
||||
// don't access "child" here the background thread might already be running
|
||||
// the next loop iteration
|
||||
if (loadChildrenTask == thisTask) { |
||||
this.Children.Insert(this.Children.Count - 1, newChild); |
||||
} |
||||
}), child); |
||||
} |
||||
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action( |
||||
delegate { |
||||
if (loadChildrenTask == thisTask) { |
||||
this.Children.RemoveAt(this.Children.Count - 1); // remove 'Loading...'
|
||||
} |
||||
})); |
||||
return result; |
||||
}, ct); |
||||
loadChildrenTask = thisTask; |
||||
thisTask.Start(); |
||||
// Give the task a bit time to complete before we return to WPF - this keeps "Loading..."
|
||||
// from showing up for very short waits.
|
||||
thisTask.Wait(TimeSpan.FromMilliseconds(200)); |
||||
} |
||||
|
||||
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) |
||||
{ |
||||
var loadChildrenTask = this.loadChildrenTask; |
||||
if (loadChildrenTask == null) { |
||||
App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(EnsureLazyChildren)); |
||||
loadChildrenTask = this.loadChildrenTask; |
||||
} |
||||
if (loadChildrenTask != null) { |
||||
foreach (var child in loadChildrenTask.Result) { |
||||
child.Decompile(language, output, options); |
||||
} |
||||
} |
||||
} |
||||
|
||||
sealed class LoadingTreeNode : ILSpyTreeNode<ILSpyTreeNodeBase> |
||||
{ |
||||
public override object Text { |
||||
get { return "Loading..."; } |
||||
} |
||||
|
||||
public override FilterResult Filter(FilterSettings settings) |
||||
{ |
||||
return FilterResult.Match; |
||||
} |
||||
|
||||
public override void Decompile(Language language, ICSharpCode.Decompiler.ITextOutput output, DecompilationOptions options) |
||||
{ |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue