Browse Source

Implemented WaitAdorner for long-running decompilation tasks.

pull/1/head
Daniel Grunwald 15 years ago
parent
commit
44571c7e34
  1. 3
      ILSpy/ILSpy.csproj
  2. 12
      ILSpy/MainWindow.xaml
  3. 5
      ILSpy/MainWindow.xaml.cs
  4. 48
      ILSpy/TextView/DecompilerTextView.cs
  5. 24
      ILSpy/TextView/DecompilerTextView.xaml

3
ILSpy/ILSpy.csproj

@ -130,6 +130,9 @@
<Page Include="AboutDialog.xaml" /> <Page Include="AboutDialog.xaml" />
<Page Include="MainWindow.xaml" /> <Page Include="MainWindow.xaml" />
<Page Include="OpenFromGacDialog.xaml" /> <Page Include="OpenFromGacDialog.xaml" />
<Page Include="TextView\DecompilerTextView.xaml">
<DependentUpon>DecompilerTextView.cs</DependentUpon>
</Page>
<Page Include="themes\generic.xaml" /> <Page Include="themes\generic.xaml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

12
ILSpy/MainWindow.xaml

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Window <Window
x:Class="ICSharpCode.ILSpy.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:tv="clr-namespace:ICSharpCode.TreeView;assembly=ICSharpCode.TreeView" xmlns:ae="clr-namespace:ICSharpCode.AvalonEdit;assembly=ICSharpCode.AvalonEdit" x:Class="ICSharpCode.ILSpy.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:tv="clr-namespace:ICSharpCode.TreeView;assembly=ICSharpCode.TreeView"
xmlns:local="clr-namespace:ICSharpCode.ILSpy" xmlns:local="clr-namespace:ICSharpCode.ILSpy" xmlns:textView="clr-namespace:ICSharpCode.ILSpy.TextView"
Title="ILSpy" Title="ILSpy"
Width="790" Width="790"
Height="500" Height="500"
@ -103,13 +103,7 @@
<!-- Right pane: Text Editor --> <!-- Right pane: Text Editor -->
<DockPanel <DockPanel
Grid.Column="2"> Grid.Column="2">
<ae:TextEditor <textView:DecompilerTextView x:Name="decompilerTextView" />
Name="textEditor"
FontFamily="Consolas"
FontSize="10pt"
IsReadOnly="True"
Background="{DynamicResource {x:Static SystemColors.InfoBrushKey}}"
Foreground="{DynamicResource {x:Static SystemColors.InfoTextBrushKey}}" />
</DockPanel> </DockPanel>
</Grid> </Grid>
</DockPanel> </DockPanel>

5
ILSpy/MainWindow.xaml.cs

@ -45,7 +45,6 @@ namespace ICSharpCode.ILSpy
public partial class MainWindow : Window public partial class MainWindow : Window
{ {
AssemblyList assemblyList = new AssemblyList(); AssemblyList assemblyList = new AssemblyList();
DecompilerTextView decompilerTextView;
FilterSettings filterSettings = new FilterSettings(); FilterSettings filterSettings = new FilterSettings();
static readonly System.Reflection.Assembly[] initialAssemblies = { static readonly System.Reflection.Assembly[] initialAssemblies = {
@ -67,15 +66,13 @@ namespace ICSharpCode.ILSpy
{ {
this.DataContext = filterSettings; this.DataContext = filterSettings;
InitializeComponent(); InitializeComponent();
decompilerTextView = new DecompilerTextView(this, textEditor); decompilerTextView.mainWindow = this;
languageComboBox.Items.Add(new Decompiler.CSharpLanguage()); languageComboBox.Items.Add(new Decompiler.CSharpLanguage());
languageComboBox.Items.Add(new Disassembler.ILLanguage(false)); languageComboBox.Items.Add(new Disassembler.ILLanguage(false));
languageComboBox.Items.Add(new Disassembler.ILLanguage(true)); languageComboBox.Items.Add(new Disassembler.ILLanguage(true));
languageComboBox.SelectedItem = languageComboBox.Items[0]; languageComboBox.SelectedItem = languageComboBox.Items[0];
textEditor.Text = "Welcome to ILSpy!";
AssemblyListTreeNode assemblyListTreeNode = new AssemblyListTreeNode(assemblyList); AssemblyListTreeNode assemblyListTreeNode = new AssemblyListTreeNode(assemblyList);
assemblyListTreeNode.FilterSettings = filterSettings.Clone(); assemblyListTreeNode.FilterSettings = filterSettings.Clone();
filterSettings.PropertyChanged += delegate { filterSettings.PropertyChanged += delegate {

48
ILSpy/TextView/DecompilerTextView.cs

@ -6,8 +6,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
using System.Windows.Threading; using System.Windows.Threading;
using ICSharpCode.AvalonEdit; using ICSharpCode.AvalonEdit;
using Mono.Cecil; using Mono.Cecil;
@ -16,39 +18,41 @@ namespace ICSharpCode.ILSpy.TextView
/// <summary> /// <summary>
/// Manages the TextEditor showing the decompiled code. /// Manages the TextEditor showing the decompiled code.
/// </summary> /// </summary>
sealed class DecompilerTextView sealed partial class DecompilerTextView : UserControl
{ {
readonly MainWindow mainWindow;
readonly TextEditor textEditor;
readonly ReferenceElementGenerator referenceElementGenerator; readonly ReferenceElementGenerator referenceElementGenerator;
internal MainWindow mainWindow;
DefinitionLookup definitionLookup; DefinitionLookup definitionLookup;
CancellationTokenSource currentCancellationTokenSource; CancellationTokenSource currentCancellationTokenSource;
public DecompilerTextView(MainWindow mainWindow, TextEditor textEditor) public DecompilerTextView()
{ {
if (mainWindow == null) InitializeComponent();
throw new ArgumentNullException("mainWindow");
if (textEditor == null)
throw new ArgumentNullException("textEditor");
this.mainWindow = mainWindow;
this.textEditor = textEditor;
this.referenceElementGenerator = new ReferenceElementGenerator(this); this.referenceElementGenerator = new ReferenceElementGenerator(this);
textEditor.TextArea.TextView.ElementGenerators.Add(referenceElementGenerator); textEditor.TextArea.TextView.ElementGenerators.Add(referenceElementGenerator);
textEditor.Text = "Welcome to ILSpy!";
} }
public void Decompile(IEnumerable<ILSpyTreeNodeBase> treeNodes) public void Decompile(IEnumerable<ILSpyTreeNodeBase> treeNodes)
{ {
if (currentCancellationTokenSource != null) if (waitAdorner.Visibility != Visibility.Visible) {
currentCancellationTokenSource.Cancel(); waitAdorner.Visibility = Visibility.Visible;
waitAdorner.BeginAnimation(OpacityProperty, new DoubleAnimation(0, 1, new Duration(TimeSpan.FromSeconds(0.5)), FillBehavior.Stop));
}
CancellationTokenSource previousCancellationTokenSource = currentCancellationTokenSource;
var myCancellationTokenSource = new CancellationTokenSource(); var myCancellationTokenSource = new CancellationTokenSource();
currentCancellationTokenSource = myCancellationTokenSource; currentCancellationTokenSource = myCancellationTokenSource;
var task = RunDecompiler(Language.Current, treeNodes.ToArray(), myCancellationTokenSource.Token); // cancel the previous only after current was set to the new one (avoid that the old one still finishes successfully)
if (previousCancellationTokenSource != null)
previousCancellationTokenSource.Cancel();
var task = RunDecompiler(ILSpy.Language.Current, treeNodes.ToArray(), myCancellationTokenSource.Token);
task.ContinueWith( task.ContinueWith(
delegate { delegate {
try { try {
if (currentCancellationTokenSource == myCancellationTokenSource) { if (currentCancellationTokenSource == myCancellationTokenSource) {
currentCancellationTokenSource = null; currentCancellationTokenSource = null;
waitAdorner.Visibility = Visibility.Collapsed;
try { try {
SmartTextOutput textOutput = task.Result; SmartTextOutput textOutput = task.Result;
referenceElementGenerator.References = textOutput.References; referenceElementGenerator.References = textOutput.References;
@ -61,6 +65,12 @@ namespace ICSharpCode.ILSpy.TextView
definitionLookup = null; definitionLookup = null;
textEditor.Text = string.Join(Environment.NewLine, ex.InnerExceptions.Select(ie => ie.ToString())); textEditor.Text = string.Join(Environment.NewLine, ex.InnerExceptions.Select(ie => ie.ToString()));
} }
} else {
try {
task.Wait();
} catch (AggregateException) {
// observe the exception (otherwise the task's finalizer will shut down the AppDomain)
}
} }
} finally { } finally {
myCancellationTokenSource.Dispose(); myCancellationTokenSource.Dispose();
@ -69,7 +79,7 @@ namespace ICSharpCode.ILSpy.TextView
TaskScheduler.FromCurrentSynchronizationContext()); TaskScheduler.FromCurrentSynchronizationContext());
} }
static Task<SmartTextOutput> RunDecompiler(Language language, ILSpyTreeNodeBase[] nodes, CancellationToken cancellationToken) static Task<SmartTextOutput> RunDecompiler(ILSpy.Language language, ILSpyTreeNodeBase[] nodes, CancellationToken cancellationToken)
{ {
return Task.Factory.StartNew( return Task.Factory.StartNew(
delegate { delegate {
@ -91,7 +101,7 @@ namespace ICSharpCode.ILSpy.TextView
textEditor.TextArea.Focus(); textEditor.TextArea.Focus();
textEditor.Select(pos, 0); textEditor.Select(pos, 0);
textEditor.ScrollTo(textEditor.TextArea.Caret.Line, textEditor.TextArea.Caret.Column); textEditor.ScrollTo(textEditor.TextArea.Caret.Line, textEditor.TextArea.Caret.Column);
mainWindow.Dispatcher.Invoke(DispatcherPriority.Background, new Action( Dispatcher.Invoke(DispatcherPriority.Background, new Action(
delegate { delegate {
CaretHighlightAdorner.DisplayCaretHighlightAnimation(textEditor.TextArea); CaretHighlightAdorner.DisplayCaretHighlightAnimation(textEditor.TextArea);
})); }));
@ -113,5 +123,11 @@ namespace ICSharpCode.ILSpy.TextView
mainWindow.SelectNode(assemblyList.Assemblies.FirstOrDefault(node => node.AssemblyDefinition == reference)); mainWindow.SelectNode(assemblyList.Assemblies.FirstOrDefault(node => node.AssemblyDefinition == reference));
} }
} }
void cancelButton_Click(object sender, RoutedEventArgs e)
{
if (currentCancellationTokenSource != null)
currentCancellationTokenSource.Cancel();
}
} }
} }

24
ILSpy/TextView/DecompilerTextView.xaml

@ -0,0 +1,24 @@
<UserControl x:Class="ICSharpCode.ILSpy.TextView.DecompilerTextView" x:ClassModifier="internal" x:Name="self"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ae="clr-namespace:ICSharpCode.AvalonEdit;assembly=ICSharpCode.AvalonEdit">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="boolToVisibility" />
</UserControl.Resources>
<Grid>
<ae:TextEditor
Name="textEditor"
FontFamily="Consolas"
FontSize="10pt"
IsReadOnly="True"
Background="{DynamicResource {x:Static SystemColors.InfoBrushKey}}"
Foreground="{DynamicResource {x:Static SystemColors.InfoTextBrushKey}}" />
<Border Name="waitAdorner" Background="#80FFFFFF">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock FontSize="14pt">Decompiling...</TextBlock>
<ProgressBar IsIndeterminate="True" Height="16" Margin="0, 4" />
<Button Click="cancelButton_Click" HorizontalAlignment="Center">Cancel</Button>
</StackPanel>
</Border>
</Grid>
</UserControl>
Loading…
Cancel
Save