2121using System . Collections . Specialized ;
2222using System . ComponentModel ;
2323using System . Composition ;
24+ using System . Diagnostics ;
2425using System . Diagnostics . CodeAnalysis ;
2526using System . IO ;
2627using 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 ( ) ;
0 commit comments