Browse Source

Implemented WaitAdorner for long-running decompilation tasks.

pull/1/head
Daniel Grunwald 14 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 @@ @@ -130,6 +130,9 @@
<Page Include="AboutDialog.xaml" />
<Page Include="MainWindow.xaml" />
<Page Include="OpenFromGacDialog.xaml" />
<Page Include="TextView\DecompilerTextView.xaml">
<DependentUpon>DecompilerTextView.cs</DependentUpon>
</Page>
<Page Include="themes\generic.xaml" />
</ItemGroup>
<ItemGroup>

12
ILSpy/MainWindow.xaml

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<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"
xmlns:local="clr-namespace:ICSharpCode.ILSpy"
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:textView="clr-namespace:ICSharpCode.ILSpy.TextView"
Title="ILSpy"
Width="790"
Height="500"
@ -103,13 +103,7 @@ @@ -103,13 +103,7 @@
<!-- Right pane: Text Editor -->
<DockPanel
Grid.Column="2">
<ae:TextEditor
Name="textEditor"
FontFamily="Consolas"
FontSize="10pt"
IsReadOnly="True"
Background="{DynamicResource {x:Static SystemColors.InfoBrushKey}}"
Foreground="{DynamicResource {x:Static SystemColors.InfoTextBrushKey}}" />
<textView:DecompilerTextView x:Name="decompilerTextView" />
</DockPanel>
</Grid>
</DockPanel>

5
ILSpy/MainWindow.xaml.cs

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

48
ILSpy/TextView/DecompilerTextView.cs

@ -6,8 +6,10 @@ using System.Collections.Generic; @@ -6,8 +6,10 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
using System.Windows.Threading;
using ICSharpCode.AvalonEdit;
using Mono.Cecil;
@ -16,39 +18,41 @@ namespace ICSharpCode.ILSpy.TextView @@ -16,39 +18,41 @@ namespace ICSharpCode.ILSpy.TextView
/// <summary>
/// Manages the TextEditor showing the decompiled code.
/// </summary>
sealed class DecompilerTextView
sealed partial class DecompilerTextView : UserControl
{
readonly MainWindow mainWindow;
readonly TextEditor textEditor;
readonly ReferenceElementGenerator referenceElementGenerator;
internal MainWindow mainWindow;
DefinitionLookup definitionLookup;
CancellationTokenSource currentCancellationTokenSource;
public DecompilerTextView(MainWindow mainWindow, TextEditor textEditor)
public DecompilerTextView()
{
if (mainWindow == null)
throw new ArgumentNullException("mainWindow");
if (textEditor == null)
throw new ArgumentNullException("textEditor");
this.mainWindow = mainWindow;
this.textEditor = textEditor;
InitializeComponent();
this.referenceElementGenerator = new ReferenceElementGenerator(this);
textEditor.TextArea.TextView.ElementGenerators.Add(referenceElementGenerator);
textEditor.Text = "Welcome to ILSpy!";
}
public void Decompile(IEnumerable<ILSpyTreeNodeBase> treeNodes)
{
if (currentCancellationTokenSource != null)
currentCancellationTokenSource.Cancel();
if (waitAdorner.Visibility != Visibility.Visible) {
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();
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(
delegate {
try {
if (currentCancellationTokenSource == myCancellationTokenSource) {
currentCancellationTokenSource = null;
waitAdorner.Visibility = Visibility.Collapsed;
try {
SmartTextOutput textOutput = task.Result;
referenceElementGenerator.References = textOutput.References;
@ -61,6 +65,12 @@ namespace ICSharpCode.ILSpy.TextView @@ -61,6 +65,12 @@ namespace ICSharpCode.ILSpy.TextView
definitionLookup = null;
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 {
myCancellationTokenSource.Dispose();
@ -69,7 +79,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -69,7 +79,7 @@ namespace ICSharpCode.ILSpy.TextView
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(
delegate {
@ -91,7 +101,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -91,7 +101,7 @@ namespace ICSharpCode.ILSpy.TextView
textEditor.TextArea.Focus();
textEditor.Select(pos, 0);
textEditor.ScrollTo(textEditor.TextArea.Caret.Line, textEditor.TextArea.Caret.Column);
mainWindow.Dispatcher.Invoke(DispatcherPriority.Background, new Action(
Dispatcher.Invoke(DispatcherPriority.Background, new Action(
delegate {
CaretHighlightAdorner.DisplayCaretHighlightAnimation(textEditor.TextArea);
}));
@ -113,5 +123,11 @@ namespace ICSharpCode.ILSpy.TextView @@ -113,5 +123,11 @@ namespace ICSharpCode.ILSpy.TextView
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 @@ @@ -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