Skip to content

Commit 26fdc39

Browse files
Fix #3476: Scroll position not restored when navigating back
1 parent bd9ee28 commit 26fdc39

File tree

5 files changed

+108
-56
lines changed

5 files changed

+108
-56
lines changed

ILSpy/AssemblyTree/AssemblyTreeModel.cs

Lines changed: 93 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
using System.Collections.Specialized;
2222
using System.ComponentModel;
2323
using System.Composition;
24+
using System.Diagnostics;
2425
using System.Diagnostics.CodeAnalysis;
2526
using System.IO;
2627
using System.Linq;
@@ -65,7 +66,7 @@ public class AssemblyTreeModel : ToolPaneModel
6566
private readonly DispatcherThrottle refreshThrottle;
6667

6768
private readonly NavigationHistory<NavigationState> history = new();
68-
private bool isNavigatingHistory;
69+
private NavigationState? navigatingToState;
6970
private readonly SettingsService settingsService;
7071
private readonly LanguageService languageService;
7172
private readonly IExportProvider exportProvider;
@@ -85,6 +86,7 @@ public AssemblyTreeModel(SettingsService settingsService, LanguageService langua
8586
MessageBus<SettingsChangedEventArgs>.Subscribers += (sender, e) => Settings_PropertyChanged(sender, e);
8687
MessageBus<ApplySessionSettingsEventArgs>.Subscribers += ApplySessionSettings;
8788
MessageBus<ActiveTabPageChangedEventArgs>.Subscribers += ActiveTabPageChanged;
89+
MessageBus<TabPagesCollectionChangedEventArgs>.Subscribers += (_, e) => history.RemoveAll(s => !DockWorkspace.TabPages.Contains(s.TabPage));
8890
MessageBus<ResetLayoutEventArgs>.Subscribers += ResetLayout;
8991
MessageBus<NavigateToEventArgs>.Subscribers += (_, e) => NavigateTo(e.Request, e.InNewTabPage);
9092
MessageBus<MainWindowLoadedEventArgs>.Subscribers += (_, _) => {
@@ -153,9 +155,10 @@ public SharpTreeNode[] SelectedItems {
153155
if (selectedItems.SequenceEqual(value))
154156
return;
155157

158+
var oldSelection = selectedItems;
156159
selectedItems = value;
157160
OnPropertyChanged();
158-
TreeView_SelectionChanged();
161+
TreeView_SelectionChanged(oldSelection, selectedItems);
159162
}
160163
}
161164

@@ -733,36 +736,45 @@ private void LoadAssemblies(IEnumerable<string> fileNames, List<LoadedAssembly>?
733736

734737
#region Decompile (TreeView_SelectionChanged)
735738

736-
private void TreeView_SelectionChanged()
739+
private void TreeView_SelectionChanged(SharpTreeNode[] oldSelection, SharpTreeNode[] newSelection)
737740
{
738-
if (SelectedItems.Length <= 0)
741+
var activeTabPage = DockWorkspace.ActiveTabPage;
742+
ViewState? oldState = activeTabPage.GetState();
743+
ViewState? newState;
744+
745+
if (navigatingToState == null)
739746
{
740-
// To cancel any pending decompilation requests and show an empty tab
741-
DecompileSelectedNodes();
747+
if (oldState != null)
748+
{
749+
history.UpdateCurrent(new NavigationState(activeTabPage, oldState));
750+
}
751+
752+
newState = new ViewState { DecompiledNodes = [.. newSelection.Cast<ILSpyTreeNode>()] };
742753
}
743754
else
744755
{
745-
var activeTabPage = DockWorkspace.ActiveTabPage;
746-
747-
if (!isNavigatingHistory)
748-
{
749-
history.Record(new NavigationState(activeTabPage, SelectedItems));
750-
}
756+
newState = navigatingToState.ViewState;
757+
}
751758

759+
if (newSelection.Length == 0)
760+
{
761+
// To cancel any pending decompilation requests and show an empty tab
762+
DecompileSelectedNodes(newState);
763+
}
764+
else
765+
{
752766
var delayDecompilationRequestDueToContextMenu = Mouse.RightButton == MouseButtonState.Pressed;
753767

754768
if (!delayDecompilationRequestDueToContextMenu)
755769
{
756-
var decompiledNodes = activeTabPage
757-
.GetState()
758-
?.DecompiledNodes
770+
var previousNodes = oldState?.DecompiledNodes
759771
?.Select(n => FindNodeByPath(GetPathForNode(n), true))
760772
.ExceptNullItems()
761773
.ToArray() ?? [];
762774

763-
if (!decompiledNodes.SequenceEqual(SelectedItems))
775+
if (!previousNodes.SequenceEqual(SelectedItems))
764776
{
765-
DecompileSelectedNodes();
777+
DecompileSelectedNodes(newState);
766778
}
767779
}
768780
else
@@ -790,7 +802,7 @@ void ContextMenuClosed(object? sender, EventArgs e)
790802
}
791803
}
792804

793-
public void DecompileSelectedNodes(DecompilerTextViewState? newState = null)
805+
public void DecompileSelectedNodes(ViewState? newState = null)
794806
{
795807
var activeTabPage = DockWorkspace.ActiveTabPage;
796808

@@ -801,6 +813,11 @@ public void DecompileSelectedNodes(DecompilerTextViewState? newState = null)
801813

802814
activeTabPage.SupportsLanguageSwitching = true;
803815

816+
if (newState != null && navigatingToState == null)
817+
{
818+
history.Record(new NavigationState(activeTabPage, newState));
819+
}
820+
804821
if (SelectedItems.Length == 1)
805822
{
806823
if (SelectedItem is ILSpyTreeNode node && node.View(activeTabPage))
@@ -813,7 +830,7 @@ public void DecompileSelectedNodes(DecompilerTextViewState? newState = null)
813830
}
814831

815832
var options = activeTabPage.CreateDecompilationOptions();
816-
options.TextViewState = newState;
833+
options.TextViewState = newState as DecompilerTextViewState;
817834
activeTabPage.ShowTextViewAsync(textView => textView.DecompileAsync(this.CurrentLanguage, this.SelectedNodes, options));
818835
}
819836

@@ -834,26 +851,30 @@ public void NavigateHistory(bool forward)
834851
{
835852
try
836853
{
837-
isNavigatingHistory = true;
838-
839854
TabPageModel tabPage = DockWorkspace.ActiveTabPage;
840855
var state = tabPage.GetState();
841856
if (state != null)
842857
history.UpdateCurrent(new NavigationState(tabPage, state));
843858
var newState = forward ? history.GoForward() : history.GoBack();
859+
navigatingToState = newState;
844860

845861
TabPageModel activeTabPage = newState.TabPage;
846862

847-
if (!DockWorkspace.TabPages.Contains(activeTabPage))
848-
DockWorkspace.AddTabPage(activeTabPage);
849-
else
850-
DockWorkspace.ActiveTabPage = activeTabPage;
863+
Debug.Assert(DockWorkspace.TabPages.Contains(activeTabPage));
864+
DockWorkspace.ActiveTabPage = activeTabPage;
851865

852-
SelectNodes(newState.TreeNodes);
866+
if (newState.TreeNodes.Any())
867+
{
868+
SelectNodes(newState.TreeNodes);
869+
}
870+
else if (newState.ViewState.ViewedUri != null)
871+
{
872+
NavigateTo(new(newState.ViewState.ViewedUri, null));
873+
}
853874
}
854875
finally
855876
{
856-
isNavigatingHistory = false;
877+
navigatingToState = null;
857878
}
858879
}
859880

@@ -863,21 +884,46 @@ public void NavigateHistory(bool forward)
863884

864885
private void NavigateTo(RequestNavigateEventArgs e, bool inNewTabPage = false)
865886
{
866-
if (e.Uri.Scheme == "resource")
887+
if (e.Uri.Scheme != "resource")
867888
{
868-
if (inNewTabPage)
889+
return;
890+
}
891+
892+
TabPageModel tabPage = DockWorkspace.ActiveTabPage;
893+
ViewState? oldState = tabPage.GetState();
894+
ViewState? newState;
895+
896+
if (navigatingToState == null)
897+
{
898+
if (oldState != null)
869899
{
870-
DockWorkspace.AddTabPage();
900+
history.UpdateCurrent(new NavigationState(tabPage, oldState));
871901
}
872902

873-
if (e.Uri.Host == "aboutpage")
903+
newState = new ViewState { ViewedUri = e.Uri };
904+
905+
if (inNewTabPage)
874906
{
875-
RecordHistory();
876-
MessageBus.Send(this, new ShowAboutPageEventArgs(DockWorkspace.ActiveTabPage));
877-
e.Handled = true;
878-
return;
907+
tabPage = DockWorkspace.AddTabPage();
879908
}
909+
}
910+
else
911+
{
912+
newState = navigatingToState.ViewState;
913+
tabPage = DockWorkspace.ActiveTabPage = navigatingToState.TabPage;
914+
}
915+
916+
bool needsNewNavigationEntry = !inNewTabPage && selectedItems?.Length == 0;
917+
918+
UnselectAll();
880919

920+
if (e.Uri.Host == "aboutpage")
921+
{
922+
MessageBus.Send(this, new ShowAboutPageEventArgs(DockWorkspace.ActiveTabPage));
923+
e.Handled = true;
924+
}
925+
else
926+
{
881927
AvalonEditTextOutput output = new AvalonEditTextOutput {
882928
Address = e.Uri,
883929
Title = e.Uri.AbsolutePath,
@@ -896,23 +942,22 @@ private void NavigateTo(RequestNavigateEventArgs e, bool inNewTabPage = false)
896942
}
897943
}
898944
}
899-
RecordHistory();
900945
DockWorkspace.ShowText(output);
901946
e.Handled = true;
902947
}
903948

904-
void RecordHistory()
949+
if (navigatingToState == null)
905950
{
906-
if (isNavigatingHistory)
907-
return;
908-
TabPageModel tabPage = DockWorkspace.ActiveTabPage;
909-
var currentState = tabPage.GetState();
910-
if (currentState != null)
911-
history.UpdateCurrent(new NavigationState(tabPage, currentState));
912-
913-
UnselectAll();
914-
915-
history.Record(new NavigationState(tabPage, new ViewState { ViewedUri = e.Uri }));
951+
// the call to UnselectAll() above already creates a new navigation entry,
952+
// we just need to make sure it contains something useful.
953+
if (!needsNewNavigationEntry)
954+
{
955+
history.UpdateCurrent(new NavigationState(tabPage, tabPage.GetState()));
956+
}
957+
else
958+
{
959+
history.Record(new NavigationState(tabPage, tabPage.GetState()));
960+
}
916961
}
917962
}
918963

@@ -1039,8 +1084,8 @@ private void ActiveTabPageChanged(object? sender, ActiveTabPageChangedEventArgs
10391084
{
10401085
NavigateTo(new(state.ViewedUri, null));
10411086
}
1042-
10431087
}
1088+
10441089
private void ResetLayout(object? sender, ResetLayoutEventArgs e)
10451090
{
10461091
RefreshDecompiledView();

ILSpy/Commands/DecompileInNewViewCommand.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,12 @@
2020
using System.Collections.Generic;
2121
using System.Composition;
2222
using System.Linq;
23-
using System.Windows.Threading;
2423

2524
using ICSharpCode.Decompiler.TypeSystem;
2625
using ICSharpCode.ILSpy.AssemblyTree;
2726
using ICSharpCode.ILSpy.Docking;
2827
using ICSharpCode.ILSpy.Properties;
2928
using ICSharpCode.ILSpy.TreeNodes;
30-
using ICSharpCode.ILSpy.ViewModels;
3129

3230
using TomsToolbox.Essentials;
3331

@@ -49,11 +47,7 @@ public bool IsEnabled(TextViewContext context)
4947

5048
public void Execute(TextViewContext context)
5149
{
52-
var activePane = dockWorkspace.ActivePane;
53-
5450
DecompileNodes(GetNodes(context).ToArray());
55-
56-
dockWorkspace.ActivePane = activePane;
5751
}
5852

5953
IEnumerable<ILSpyTreeNode> GetNodes(TextViewContext context)
@@ -91,7 +85,7 @@ void DecompileNodes(ILSpyTreeNode[] nodes)
9185
if (nodes.Length == 0)
9286
return;
9387

94-
dockWorkspace.AddTabPage();
88+
dockWorkspace.ActiveTabPage = dockWorkspace.AddTabPage();
9589

9690
if (assemblyTreeModel.SelectedItems.SequenceEqual(nodes))
9791
assemblyTreeModel.DecompileSelectedNodes();

ILSpy/Docking/DockWorkspace.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ private void TabPages_CollectionChanged(object sender, NotifyCollectionChangedEv
116116
{
117117
item.IsCloseable = canClose;
118118
}
119+
120+
MessageBus.Send(this, new TabPagesCollectionChangedEventArgs(e));
119121
}
120122

121123
public TabPageModel AddTabPage(TabPageModel tabPage = null)

ILSpy/TextView/DecompilerTextView.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1343,7 +1343,7 @@ public FoldingManager? FoldingManager {
13431343
#endregion
13441344
}
13451345

1346-
[DebuggerDisplay("Nodes = {DecompiledNodes}, ViewedUri = {ViewedUri}")]
1346+
[DebuggerDisplay($"{{{nameof(GetDebuggerDisplay)}(),nq}}")]
13471347
public class ViewState : IEquatable<ViewState>
13481348
{
13491349
public HashSet<ILSpyTreeNode>? DecompiledNodes;
@@ -1364,6 +1364,11 @@ static bool NullSafeSetEquals(HashSet<ILSpyTreeNode>? a, HashSet<ILSpyTreeNode>?
13641364
return a.SetEquals(b);
13651365
}
13661366
}
1367+
1368+
protected virtual string GetDebuggerDisplay()
1369+
{
1370+
return $"Nodes = {DecompiledNodes?.Count.ToString() ?? "<null>"}, ViewedUri = {ViewedUri?.ToString() ?? "<null>"}";
1371+
}
13671372
}
13681373

13691374
public class DecompilerTextViewState : ViewState
@@ -1432,6 +1437,11 @@ public override bool Equals(ViewState? other)
14321437
}
14331438
return false;
14341439
}
1440+
1441+
protected override string GetDebuggerDisplay()
1442+
{
1443+
return $"{base.GetDebuggerDisplay()}, ExpandMemberDefinitions = {ExpandMemberDefinitions}, VerticalOffset = {VerticalOffset}, HorizontalOffset = {HorizontalOffset}, FoldingsChecksum = {FoldingsChecksum}";
1444+
}
14351445
}
14361446

14371447
static class ExtensionMethods

ILSpy/Util/MessageBus.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ public static implicit operator T(WrappedEventArgs<T> outer)
7575
}
7676

7777
public class CurrentAssemblyListChangedEventArgs(NotifyCollectionChangedEventArgs e) : WrappedEventArgs<NotifyCollectionChangedEventArgs>(e);
78+
public class TabPagesCollectionChangedEventArgs(NotifyCollectionChangedEventArgs e) : WrappedEventArgs<NotifyCollectionChangedEventArgs>(e);
7879

7980
public class SettingsChangedEventArgs(PropertyChangedEventArgs e) : WrappedEventArgs<PropertyChangedEventArgs>(e);
8081

0 commit comments

Comments
 (0)