diff --git a/ICSharpCode.ILSpyX/AssemblyList.cs b/ICSharpCode.ILSpyX/AssemblyList.cs
index ec10a4e92..190f45e52 100644
--- a/ICSharpCode.ILSpyX/AssemblyList.cs
+++ b/ICSharpCode.ILSpyX/AssemblyList.cs
@@ -186,7 +186,7 @@ namespace ICSharpCode.ILSpyX
 			get { return listName; }
 		}
 
-		internal void Move(LoadedAssembly[] assembliesToMove, int index)
+		public void Move(LoadedAssembly[] assembliesToMove, int index)
 		{
 			VerifyAccess();
 			lock (lockObj)
@@ -230,7 +230,7 @@ namespace ICSharpCode.ILSpyX
 			}
 		}
 
-		internal void RefreshSave()
+		public void RefreshSave()
 		{
 			// Whenever the assembly list is modified, mark it as dirty
 			// and enqueue a task that saves it once the UI has finished modifying the assembly list.
diff --git a/ICSharpCode.ILSpyX/Extensions/CollectionExtensions.cs b/ICSharpCode.ILSpyX/Extensions/CollectionExtensions.cs
index 772c46476..1d4f359e1 100644
--- a/ICSharpCode.ILSpyX/Extensions/CollectionExtensions.cs
+++ b/ICSharpCode.ILSpyX/Extensions/CollectionExtensions.cs
@@ -27,7 +27,7 @@ namespace ICSharpCode.ILSpyX.Extensions
 {
 	public static class CollectionExtensions
 	{
-		public static void AddRange<T>(this ICollection<T> list, IEnumerable<T> items)
+		internal static void AddRange<T>(this ICollection<T> list, IEnumerable<T> items)
 		{
 			foreach (T item in items)
 				if (!list.Contains(item))
diff --git a/ICSharpCode.ILSpyX/ICSharpCode.ILSpyX.csproj b/ICSharpCode.ILSpyX/ICSharpCode.ILSpyX.csproj
index bcea038e2..21a9363b0 100644
--- a/ICSharpCode.ILSpyX/ICSharpCode.ILSpyX.csproj
+++ b/ICSharpCode.ILSpyX/ICSharpCode.ILSpyX.csproj
@@ -41,7 +41,6 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <InternalsVisibleTo Include="ILSpy" Key="00240000048000009400000006020000002400005253413100040000010001004dcf3979c4e902efa4dd2163a039701ed5822e6f1134d77737296abbb97bf0803083cfb2117b4f5446a217782f5c7c634f9fe1fc60b4c11d62c5b3d33545036706296d31903ddcf750875db38a8ac379512f51620bb948c94d0831125fbc5fe63707cbb93f48c1459c4d1749eb7ac5e681a2f0d6d7c60fa527a3c0b8f92b02bf" />
     <InternalsVisibleTo Include="ILSpy.Tests" Key="00240000048000009400000006020000002400005253413100040000010001004dcf3979c4e902efa4dd2163a039701ed5822e6f1134d77737296abbb97bf0803083cfb2117b4f5446a217782f5c7c634f9fe1fc60b4c11d62c5b3d33545036706296d31903ddcf750875db38a8ac379512f51620bb948c94d0831125fbc5fe63707cbb93f48c1459c4d1749eb7ac5e681a2f0d6d7c60fa527a3c0b8f92b02bf" />
   </ItemGroup>
 
diff --git a/ICSharpCode.ILSpyX/LoadedPackage.cs b/ICSharpCode.ILSpyX/LoadedPackage.cs
index 47e80b962..78f80b349 100644
--- a/ICSharpCode.ILSpyX/LoadedPackage.cs
+++ b/ICSharpCode.ILSpyX/LoadedPackage.cs
@@ -51,14 +51,14 @@ namespace ICSharpCode.ILSpyX
 
 		public PackageKind Kind { get; }
 
-		internal SingleFileBundle.Header BundleHeader { get; set; }
+		public SingleFileBundle.Header BundleHeader { get; set; }
 
 		/// <summary>
 		/// List of all entries, including those in sub-directories within the package.
 		/// </summary>
 		public IReadOnlyList<PackageEntry> Entries { get; }
 
-		internal PackageFolder RootFolder { get; }
+		public PackageFolder RootFolder { get; }
 
 		public LoadedPackage(PackageKind kind, IEnumerable<PackageEntry> entries)
 		{
@@ -256,7 +256,7 @@ namespace ICSharpCode.ILSpyX
 		public abstract string FullName { get; }
 	}
 
-	sealed class PackageFolder : IAssemblyResolver
+	public sealed class PackageFolder : IAssemblyResolver
 	{
 		/// <summary>
 		/// Gets the short name of the folder.
@@ -326,7 +326,7 @@ namespace ICSharpCode.ILSpyX
 
 		readonly Dictionary<string, LoadedAssembly?> assemblies = new Dictionary<string, LoadedAssembly?>(StringComparer.OrdinalIgnoreCase);
 
-		internal LoadedAssembly? ResolveFileName(string name)
+		public LoadedAssembly? ResolveFileName(string name)
 		{
 			if (package.LoadedAssembly == null)
 				return null;
diff --git a/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs b/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs
index ec4cb8faf..a5432f47c 100644
--- a/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs
+++ b/ICSharpCode.ILSpyX/PdbProvider/PortableDebugInfoProvider.cs
@@ -32,7 +32,7 @@ using static ICSharpCode.Decompiler.Metadata.MetadataFile;
 
 namespace ICSharpCode.ILSpyX.PdbProvider
 {
-	class PortableDebugInfoProvider : IDebugInfoProvider
+	public class PortableDebugInfoProvider : IDebugInfoProvider
 	{
 		string? pdbFileName;
 		string moduleFileName;
@@ -40,7 +40,7 @@ namespace ICSharpCode.ILSpyX.PdbProvider
 		MetadataReaderOptions options;
 		bool hasError;
 
-		internal bool IsEmbedded => pdbFileName == null;
+		public bool IsEmbedded => pdbFileName == null;
 
 		public PortableDebugInfoProvider(string moduleFileName, MetadataReaderProvider provider,
 			MetadataReaderOptions options = MetadataReaderOptions.Default,
@@ -69,7 +69,7 @@ namespace ICSharpCode.ILSpyX.PdbProvider
 			}
 		}
 
-		internal MetadataReader? GetMetadataReader()
+		public MetadataReader? GetMetadataReader()
 		{
 			try
 			{
diff --git a/ICSharpCode.ILSpyX/TreeView/SharpTreeNode.cs b/ICSharpCode.ILSpyX/TreeView/SharpTreeNode.cs
index e34675fc3..3fd6bb662 100644
--- a/ICSharpCode.ILSpyX/TreeView/SharpTreeNode.cs
+++ b/ICSharpCode.ILSpyX/TreeView/SharpTreeNode.cs
@@ -182,7 +182,7 @@ namespace ICSharpCode.ILSpyX.TreeView
 		#endregion
 
 		#region OnChildrenChanged
-		protected internal virtual void OnChildrenChanged(NotifyCollectionChangedEventArgs e)
+		public virtual void OnChildrenChanged(NotifyCollectionChangedEventArgs e)
 		{
 			if (e.OldItems != null)
 			{
@@ -359,7 +359,7 @@ namespace ICSharpCode.ILSpyX.TreeView
 			return TreeTraversal.PreOrder(this.Children.Where(c => c.isVisible), n => n.Children.Where(c => c.isVisible));
 		}
 
-		internal IEnumerable<SharpTreeNode> VisibleDescendantsAndSelf()
+		public IEnumerable<SharpTreeNode> VisibleDescendantsAndSelf()
 		{
 			return TreeTraversal.PreOrder(this, n => n.Children.Where(c => c.isVisible));
 		}
@@ -637,7 +637,7 @@ namespace ICSharpCode.ILSpyX.TreeView
 			return false;
 		}
 
-		internal void InternalDrop(IPlatformDragEventArgs e, int index)
+		public void InternalDrop(IPlatformDragEventArgs e, int index)
 		{
 			if (LazyLoading)
 			{
diff --git a/ICSharpCode.ILSpyX/TreeView/TreeFlattener.cs b/ICSharpCode.ILSpyX/TreeView/TreeFlattener.cs
index 46cc5cafd..80803c194 100644
--- a/ICSharpCode.ILSpyX/TreeView/TreeFlattener.cs
+++ b/ICSharpCode.ILSpyX/TreeView/TreeFlattener.cs
@@ -26,7 +26,7 @@ using System.Diagnostics;
 
 namespace ICSharpCode.ILSpyX.TreeView
 {
-	sealed class TreeFlattener : IList, INotifyCollectionChanged
+	public sealed class TreeFlattener : IList, INotifyCollectionChanged
 	{
 		/// <summary>
 		/// The root node of the flat list tree.
diff --git a/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs b/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs
index e0ade8666..7c3d484bc 100644
--- a/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs
+++ b/ILSpy/Analyzers/AnalyzerSearchTreeNode.cs
@@ -61,7 +61,7 @@ namespace ICSharpCode.ILSpy.Analyzers
 				var context = new AnalyzerContext() {
 					CancellationToken = ct,
 					Language = Language,
-					AssemblyList = MainWindow.Instance.AssemblyTreeModel.CurrentAssemblyList
+					AssemblyList = MainWindow.Instance.AssemblyTreeModel.AssemblyList
 				};
 				var results = analyzer.Analyze(symbol, context).Select(SymbolTreeNodeFactory);
 				if (context.SortResults)
diff --git a/ILSpy/AssemblyTree/AssemblyListPane.xaml b/ILSpy/AssemblyTree/AssemblyListPane.xaml
index 8739412a8..d0f8e9733 100644
--- a/ILSpy/AssemblyTree/AssemblyListPane.xaml
+++ b/ILSpy/AssemblyTree/AssemblyListPane.xaml
@@ -1,28 +1,28 @@
 <treeView:SharpTreeView x:Class="ICSharpCode.ILSpy.AssemblyTree.AssemblyListPane"
-                  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-                  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-                  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-                  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-                  xmlns:treeView="clr-namespace:ICSharpCode.ILSpy.Controls.TreeView"
-                  xmlns:treeNodes="clr-namespace:ICSharpCode.ILSpy.TreeNodes"
-                  xmlns:assemblyTree="clr-namespace:ICSharpCode.ILSpy.AssemblyTree"
-                  xmlns:toms="urn:TomsToolbox"
-                  mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"
-                  d:DataContext="{d:DesignInstance assemblyTree:AssemblyListPaneModel}"
-                  AutomationProperties.Name="Assemblies and Classes"
-                  ShowRoot="False"
-                  AllowDropOrder="True"
-                  AllowDrop="True"
-                  BorderThickness="0" Visibility="Visible"
-				  Root="{Binding Root}"
-				  SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
-                  toms:MultiSelectorExtensions.SelectionBinding="{Binding SelectedItems}">
+						xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+						xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+						xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+						xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+						xmlns:treeView="clr-namespace:ICSharpCode.ILSpy.Controls.TreeView"
+						xmlns:treeNodes="clr-namespace:ICSharpCode.ILSpy.TreeNodes"
+						xmlns:assemblyTree="clr-namespace:ICSharpCode.ILSpy.AssemblyTree"
+						xmlns:toms="urn:TomsToolbox"
+						mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"
+						d:DataContext="{d:DesignInstance assemblyTree:AssemblyListPaneModel}"
+						AutomationProperties.Name="Assemblies and Classes"
+						ShowRoot="False"
+						AllowDropOrder="True"
+						AllowDrop="True"
+						BorderThickness="0" Visibility="Visible"
+						Root="{Binding Root}"
+						SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
+						toms:MultiSelectorExtensions.SelectionBinding="{Binding SelectedItems}">
 	<treeView:SharpTreeView.ItemContainerStyle>
 		<Style TargetType="treeView:SharpTreeViewItem">
 			<Setter Property="Template">
 				<Setter.Value>
 					<ControlTemplate TargetType="{x:Type treeView:SharpTreeViewItem}"
-					                 d:DataContext="{d:DesignInstance treeNodes:ILSpyTreeNode}">
+									 d:DataContext="{d:DesignInstance treeNodes:ILSpyTreeNode}">
 						<Border Background="Transparent">
 							<Border Background="{TemplateBinding Background}">
 								<treeView:SharpTreeNodeView x:Name="nodeView" HorizontalAlignment="Left" />
@@ -37,13 +37,13 @@
 							</DataTrigger>
 							<Trigger Property="IsSelected" Value="True">
 								<Setter TargetName="nodeView" Property="TextBackground"
-								        Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
+										Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
 								<Setter TargetName="nodeView" Property="Foreground"
-								        Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
+										Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
 							</Trigger>
 							<Trigger Property="IsEnabled" Value="False">
 								<Setter TargetName="nodeView" Property="Foreground"
-								        Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
+										Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
 							</Trigger>
 						</ControlTemplate.Triggers>
 					</ControlTemplate>
@@ -51,4 +51,4 @@
 			</Setter>
 		</Style>
 	</treeView:SharpTreeView.ItemContainerStyle>
-</treeView:SharpTreeView>
+</treeView:SharpTreeView>
\ No newline at end of file
diff --git a/ILSpy/AssemblyTree/AssemblyListPaneModel.cs b/ILSpy/AssemblyTree/AssemblyListPaneModel.cs
index 9fff284be..97199d059 100644
--- a/ILSpy/AssemblyTree/AssemblyListPaneModel.cs
+++ b/ILSpy/AssemblyTree/AssemblyListPaneModel.cs
@@ -36,7 +36,6 @@ using ICSharpCode.ILSpyX.Settings;
 using ICSharpCode.ILSpyX.TreeView;
 using System.Collections.Specialized;
 using System.ComponentModel;
-using System.Diagnostics;
 using System.Linq;
 using ICSharpCode.Decompiler.Metadata;
 
@@ -52,6 +51,7 @@ using ICSharpCode.ILSpy.Search;
 using ICSharpCode.Decompiler;
 using System.Text;
 
+using TomsToolbox.Essentials;
 using TomsToolbox.Wpf;
 
 namespace ICSharpCode.ILSpy.AssemblyTree
@@ -64,12 +64,8 @@ namespace ICSharpCode.ILSpy.AssemblyTree
 		public const string PaneContentId = "assemblyListPane";
 
 		AssemblyListPane activeView;
-		AssemblyList assemblyList;
 		AssemblyListTreeNode assemblyListTreeNode;
 
-		bool refreshInProgress;
-		bool changingActiveTab;
-
 		readonly NavigationHistoryService history = NavigationHistoryService.Instance;
 
 		public AssemblyListPaneModel()
@@ -107,9 +103,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
 			}
 		}
 
-		public AssemblyList CurrentAssemblyList {
-			get { return assemblyList; }
-		}
+		public AssemblyList AssemblyList { get; private set; }
 
 		private SharpTreeNode root;
 		public SharpTreeNode Root {
@@ -230,7 +224,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
 				SharpTreeNode node = null;
 				if (activeTreeViewPath?.Length > 0)
 				{
-					foreach (var asm in CurrentAssemblyList.GetAssemblies())
+					foreach (var asm in AssemblyList.GetAssemblies())
 					{
 						if (asm.FileName == activeTreeViewPath[0])
 						{
@@ -327,37 +321,37 @@ namespace ICSharpCode.ILSpy.AssemblyTree
 
 			if (loadPreviousAssemblies)
 			{
-				this.assemblyList = SettingsService.Instance.AssemblyListManager.LoadList(sessionSettings.ActiveAssemblyList);
+				this.AssemblyList = SettingsService.Instance.AssemblyListManager.LoadList(sessionSettings.ActiveAssemblyList);
 			}
 			else
 			{
 				SettingsService.Instance.AssemblyListManager.ClearAll();
-				this.assemblyList = SettingsService.Instance.AssemblyListManager.CreateList(AssemblyListManager.DefaultListName);
+				this.AssemblyList = SettingsService.Instance.AssemblyListManager.CreateList(AssemblyListManager.DefaultListName);
 			}
 
 			HandleCommandLineArguments(App.CommandLineArguments);
 
-			if (assemblyList.GetAssemblies().Length == 0
-				&& assemblyList.ListName == AssemblyListManager.DefaultListName
+			if (AssemblyList.GetAssemblies().Length == 0
+				&& AssemblyList.ListName == AssemblyListManager.DefaultListName
 				&& loadPreviousAssemblies)
 			{
 				LoadInitialAssemblies();
 			}
 
-			ShowAssemblyList(this.assemblyList);
+			ShowAssemblyList(this.AssemblyList);
 
 			if (sessionSettings.ActiveAutoLoadedAssembly != null
 				&& File.Exists(sessionSettings.ActiveAutoLoadedAssembly))
 			{
-				this.assemblyList.Open(sessionSettings.ActiveAutoLoadedAssembly, true);
+				this.AssemblyList.Open(sessionSettings.ActiveAutoLoadedAssembly, true);
 			}
 
-			Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() => OpenAssemblies(SettingsService.Instance.SpySettings)));
+			Dispatcher.BeginInvoke(DispatcherPriority.Loaded, OpenAssemblies);
 		}
 
-		void OpenAssemblies(ILSpySettings spySettings)
+		void OpenAssemblies()
 		{
-			HandleCommandLineArgumentsAfterShowList(App.CommandLineArguments, spySettings);
+			HandleCommandLineArgumentsAfterShowList(App.CommandLineArguments, SettingsService.Instance.SpySettings);
 
 			AvalonEditTextOutput output = new();
 			if (FormatExceptions(App.StartupExceptions.ToArray(), output))
@@ -379,7 +373,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
 		{
 			AssemblyList list = SettingsService.Instance.AssemblyListManager.LoadList(name);
 			//Only load a new list when it is a different one
-			if (list.ListName != CurrentAssemblyList.ListName)
+			if (list.ListName != AssemblyList.ListName)
 			{
 				ShowAssemblyList(list);
 				SelectNode(Root);
@@ -389,12 +383,12 @@ namespace ICSharpCode.ILSpy.AssemblyTree
 		void ShowAssemblyList(AssemblyList assemblyList)
 		{
 			history.Clear();
-			if (this.assemblyList != null)
+			if (this.AssemblyList != null)
 			{
-				this.assemblyList.CollectionChanged -= assemblyList_CollectionChanged;
+				this.AssemblyList.CollectionChanged -= assemblyList_CollectionChanged;
 			}
 
-			this.assemblyList = assemblyList;
+			this.AssemblyList = assemblyList;
 
 			assemblyList.CollectionChanged += assemblyList_CollectionChanged;
 
@@ -450,12 +444,12 @@ namespace ICSharpCode.ILSpy.AssemblyTree
 				typeof(System.Windows.FrameworkElement).Assembly
 			};
 			foreach (System.Reflection.Assembly asm in initialAssemblies)
-				assemblyList.OpenAssembly(asm.Location);
+				AssemblyList.OpenAssembly(asm.Location);
 		}
 
 		void LanguageSettings_PropertyChanged(object sender, PropertyChangedEventArgs e)
 		{
-			if (e.PropertyName == "Language" || e.PropertyName == "LanguageVersion")
+			if (e.PropertyName is nameof(LanguageSettings.Language) or nameof(LanguageSettings.LanguageVersion))
 			{
 				DecompileSelectedNodes(recordHistory: false);
 			}
@@ -496,18 +490,12 @@ namespace ICSharpCode.ILSpy.AssemblyTree
 			}
 		}
 
-		internal void SelectNodes(IEnumerable<SharpTreeNode> nodes, bool inNewTabPage = false, bool setFocus = true, bool changingTab = false, bool ignoreCompilationRequests = false)
+		internal void SelectNodes(IEnumerable<SharpTreeNode> nodes, bool ignoreCompilationRequests = false)
 		{
 			this.ignoreDecompilationRequests = ignoreCompilationRequests;
 
 			try
 			{
-
-				if (inNewTabPage)
-				{
-					DockWorkspace.Instance.AddTabPage();
-				}
-
 				// Ensure nodes exist
 				var nodesList = nodes.Select(n => FindNodeByPath(GetPathForNode(n), true))
 					.Where(n => n != null)
@@ -518,28 +506,14 @@ namespace ICSharpCode.ILSpy.AssemblyTree
 					return;
 				}
 
-				this.changingActiveTab = changingTab || inNewTabPage;
-
-				var currentFocused = Keyboard.FocusedElement;
-
-				try
+				if (SelectedItems.SequenceEqual(nodesList))
 				{
-					if (SelectedItems.SequenceEqual(nodesList))
-					{
-						Dispatcher.BeginInvoke(RefreshDecompiledView);
-						return;
-					}
-
-					this.SelectedItems.Clear();
-					this.SelectedItems.AddRange(nodesList);
+					Dispatcher.BeginInvoke(RefreshDecompiledView);
+					return;
 				}
-				finally
-				{
-					if (!setFocus)
-						currentFocused.Focus();
 
-					this.changingActiveTab = false;
-				}
+				SelectedItems.Clear();
+				SelectedItems.AddRange(nodesList);
 			}
 			finally
 			{
@@ -642,7 +616,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
 					break;
 				case EntityReference unresolvedEntity:
 					string protocol = unresolvedEntity.Protocol;
-					var file = unresolvedEntity.ResolveAssembly(assemblyList);
+					var file = unresolvedEntity.ResolveAssembly(AssemblyList);
 					if (file == null)
 					{
 						break;
@@ -681,35 +655,32 @@ namespace ICSharpCode.ILSpy.AssemblyTree
 
 		public void LoadAssemblies(IEnumerable<string> fileNames, List<LoadedAssembly> loadedAssemblies = null, bool focusNode = true)
 		{
-			var currentFocus = Keyboard.FocusedElement;
-			AssemblyTreeNode lastNode = null;
-
-			foreach (string file in fileNames)
+			using (Keyboard.FocusedElement.PreserveFocus(!focusNode))
 			{
-				var assembly = assemblyList.OpenAssembly(file);
+				AssemblyTreeNode lastNode = null;
 
-				if (loadedAssemblies != null)
+				foreach (string file in fileNames)
 				{
-					loadedAssemblies.Add(assembly);
-				}
-				else
-				{
-					var node = assemblyListTreeNode.FindAssemblyNode(assembly);
-					if (node != null && focusNode)
+					var assembly = AssemblyList.OpenAssembly(file);
+
+					if (loadedAssemblies != null)
 					{
-						lastNode = node;
-						SelectedItems.Add(node);
+						loadedAssemblies.Add(assembly);
+					}
+					else
+					{
+						var node = assemblyListTreeNode.FindAssemblyNode(assembly);
+						if (node != null && focusNode)
+						{
+							lastNode = node;
+							SelectedItems.Add(node);
+						}
 					}
 				}
-			}
-
-			if (!focusNode)
-			{
-				currentFocus?.Focus();
-			}
-			else if (lastNode != null)
-			{
-				activeView?.FocusNode(lastNode);
+				if (focusNode && lastNode != null)
+				{
+					activeView?.FocusNode(lastNode);
+				}
 			}
 		}
 
@@ -717,22 +688,11 @@ namespace ICSharpCode.ILSpy.AssemblyTree
 
 		void TreeView_SelectionChanged()
 		{
-			DecompilerTextViewState state = null;
-
-			// These are probably no longer needed and can be removed!
-			Debug.Assert(!refreshInProgress);
-			Debug.Assert(!changingActiveTab);
-
-			if (refreshInProgress || changingActiveTab)
-			{
-				state = DockWorkspace.Instance.ActiveTabPage.GetState() as DecompilerTextViewState;
-			}
-
 			var delayDecompilationRequestDueToContextMenu = Mouse.RightButton == MouseButtonState.Pressed;
 
-			if (!changingActiveTab && !delayDecompilationRequestDueToContextMenu)
+			if (!delayDecompilationRequestDueToContextMenu)
 			{
-				DecompileSelectedNodes(state);
+				DecompileSelectedNodes();
 			}
 			else
 			{
@@ -763,9 +723,6 @@ namespace ICSharpCode.ILSpy.AssemblyTree
 			if (ignoreDecompilationRequests)
 				return;
 
-			if (SelectedItems.Count == 0 && refreshInProgress)
-				return;
-
 			var activeTabPage = DockWorkspace.Instance.ActiveTabPage;
 
 			if (recordHistory)
@@ -788,6 +745,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
 				MainWindow.Instance.NavigateTo(new(newState.ViewedUri, null), recordHistory: false);
 				return;
 			}
+
 			var options = SettingsService.Instance.CreateDecompilationOptions(activeTabPage);
 			options.TextViewState = newState;
 			activeTabPage.ShowTextViewAsync(textView => textView.DecompileAsync(this.CurrentLanguage, this.SelectedNodes, options));
@@ -795,15 +753,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
 
 		public void RefreshDecompiledView()
 		{
-			try
-			{
-				refreshInProgress = true;
-				DecompileSelectedNodes();
-			}
-			finally
-			{
-				refreshInProgress = false;
-			}
+			DecompileSelectedNodes();
 		}
 
 		public Language CurrentLanguage => SettingsService.Instance.SessionSettings.LanguageSettings.Language;
@@ -821,20 +771,12 @@ namespace ICSharpCode.ILSpy.AssemblyTree
 
 		public void Refresh()
 		{
-			var currentFocus = Keyboard.FocusedElement;
-
-			try
+			using (Keyboard.FocusedElement.PreserveFocus())
 			{
-				refreshInProgress = true;
 				var path = GetPathForNode(SelectedItem);
-				ShowAssemblyList(SettingsService.Instance.AssemblyListManager.LoadList(assemblyList.ListName));
+				ShowAssemblyList(SettingsService.Instance.AssemblyListManager.LoadList(AssemblyList.ListName));
 				SelectNode(FindNodeByPath(path, true), inNewTabPage: false);
 			}
-			finally
-			{
-				refreshInProgress = false;
-				currentFocus?.Focus();
-			}
 		}
 
 		public void UnselectAll(bool ignoreCompilationRequests = false)
@@ -861,7 +803,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
 		{
 			using (activeView?.LockUpdates())
 			{
-				CurrentAssemblyList.Sort(AssemblyComparer.Instance);
+				AssemblyList.Sort(AssemblyComparer.Instance);
 			}
 		}
 
diff --git a/ILSpy/Commands/DecompileAllCommand.cs b/ILSpy/Commands/DecompileAllCommand.cs
index ef8be645e..b041bf7a7 100644
--- a/ILSpy/Commands/DecompileAllCommand.cs
+++ b/ILSpy/Commands/DecompileAllCommand.cs
@@ -49,7 +49,7 @@ namespace ICSharpCode.ILSpy
 			Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
 				AvalonEditTextOutput output = new AvalonEditTextOutput();
 				Parallel.ForEach(
-					Partitioner.Create(MainWindow.Instance.AssemblyTreeModel.CurrentAssemblyList.GetAssemblies(), loadBalance: true),
+					Partitioner.Create(MainWindow.Instance.AssemblyTreeModel.AssemblyList.GetAssemblies(), loadBalance: true),
 					new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct },
 					delegate (LoadedAssembly asm) {
 						if (!asm.HasLoadError)
diff --git a/ILSpy/Commands/DecompileInNewViewCommand.cs b/ILSpy/Commands/DecompileInNewViewCommand.cs
index 0ecc50bf8..fd83244eb 100644
--- a/ILSpy/Commands/DecompileInNewViewCommand.cs
+++ b/ILSpy/Commands/DecompileInNewViewCommand.cs
@@ -23,6 +23,7 @@ using System.Linq;
 using System.Windows.Threading;
 
 using ICSharpCode.Decompiler.TypeSystem;
+using ICSharpCode.ILSpy.Docking;
 using ICSharpCode.ILSpy.Properties;
 using ICSharpCode.ILSpy.TreeNodes;
 
@@ -84,7 +85,9 @@ namespace ICSharpCode.ILSpy.Commands
 			if (nodes.Length == 0)
 				return;
 
-			MainWindow.Instance.AssemblyTreeModel.SelectNodes(nodes, inNewTabPage: true);
+			DockWorkspace.Instance.AddTabPage();
+
+			MainWindow.Instance.AssemblyTreeModel.SelectNodes(nodes);
 		}
 	}
 }
diff --git a/ILSpy/Commands/DisassembleAllCommand.cs b/ILSpy/Commands/DisassembleAllCommand.cs
index 60c97d227..07afced39 100644
--- a/ILSpy/Commands/DisassembleAllCommand.cs
+++ b/ILSpy/Commands/DisassembleAllCommand.cs
@@ -45,7 +45,7 @@ namespace ICSharpCode.ILSpy
 			dockWorkspace.RunWithCancellation(ct => Task<AvalonEditTextOutput>.Factory.StartNew(() => {
 				AvalonEditTextOutput output = new();
 				Parallel.ForEach(
-					Partitioner.Create(MainWindow.Instance.AssemblyTreeModel.CurrentAssemblyList.GetAssemblies(), loadBalance: true),
+					Partitioner.Create(MainWindow.Instance.AssemblyTreeModel.AssemblyList.GetAssemblies(), loadBalance: true),
 					new() { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct },
 					asm => {
 						if (!asm.HasLoadError)
diff --git a/ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs b/ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs
index 73d9769a7..9cc357374 100644
--- a/ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs
+++ b/ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs
@@ -29,12 +29,12 @@ namespace ICSharpCode.ILSpy
 	{
 		public override bool CanExecute(object parameter)
 		{
-			return MainWindow.Instance.AssemblyTreeModel.CurrentAssemblyList?.GetAssemblies().Any(l => l.HasLoadError) == true;
+			return MainWindow.Instance.AssemblyTreeModel.AssemblyList?.GetAssemblies().Any(l => l.HasLoadError) == true;
 		}
 
 		public override void Execute(object parameter)
 		{
-			foreach (var asm in MainWindow.Instance.AssemblyTreeModel.CurrentAssemblyList.GetAssemblies())
+			foreach (var asm in MainWindow.Instance.AssemblyTreeModel.AssemblyList.GetAssemblies())
 			{
 				if (!asm.HasLoadError)
 					continue;
@@ -51,12 +51,12 @@ namespace ICSharpCode.ILSpy
 	{
 		public override bool CanExecute(object parameter)
 		{
-			return MainWindow.Instance.AssemblyTreeModel.CurrentAssemblyList?.Count > 0;
+			return MainWindow.Instance.AssemblyTreeModel.AssemblyList?.Count > 0;
 		}
 
 		public override void Execute(object parameter)
 		{
-			MainWindow.Instance.AssemblyTreeModel.CurrentAssemblyList?.Clear();
+			MainWindow.Instance.AssemblyTreeModel.AssemblyList?.Clear();
 		}
 	}
 }
diff --git a/ILSpy/Docking/DockWorkspace.cs b/ILSpy/Docking/DockWorkspace.cs
index a708b9327..f0b90967d 100644
--- a/ILSpy/Docking/DockWorkspace.cs
+++ b/ILSpy/Docking/DockWorkspace.cs
@@ -17,7 +17,6 @@
 // DEALINGS IN THE SOFTWARE.
 
 using System;
-using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Collections.Specialized;
 using System.Linq;
@@ -38,6 +37,7 @@ using ICSharpCode.ILSpy.ViewModels;
 using ICSharpCode.ILSpyX.Extensions;
 
 using TomsToolbox.Composition;
+using TomsToolbox.Essentials;
 using TomsToolbox.Wpf;
 
 namespace ICSharpCode.ILSpy.Docking
@@ -71,20 +71,15 @@ namespace ICSharpCode.ILSpy.Docking
 			foreach (var tab in tabPages.ToArray())
 			{
 				var state = tab.GetState();
-				if (state == null || state.DecompiledNodes == null)
-				{
+				var decompiledNodes = state?.DecompiledNodes;
+				if (decompiledNodes == null)
 					continue;
-				}
-				bool found = false;
-				foreach (var node in state.DecompiledNodes)
-				{
-					var assemblyNode = node.Ancestors().OfType<TreeNodes.AssemblyTreeNode>().LastOrDefault();
-					if (assemblyNode != null && !e.OldItems.Contains(assemblyNode.LoadedAssembly))
-					{
-						found = true;
-						break;
-					}
-				}
+
+				bool found = decompiledNodes
+					.Select(node => node.Ancestors().OfType<TreeNodes.AssemblyTreeNode>().LastOrDefault())
+					.ExceptNullItems()
+					.Any(assemblyNode => !e.OldItems.Contains(assemblyNode.LoadedAssembly));
+
 				if (!found && tabPages.Count > 1)
 				{
 					tabPages.Remove(tab);
@@ -156,22 +151,21 @@ namespace ICSharpCode.ILSpy.Docking
 				{
 					if (state.DecompiledNodes != null)
 					{
-						MainWindow.Instance.AssemblyTreeModel.SelectNodes(state.DecompiledNodes, inNewTabPage: false, setFocus: true, changingTab: true);
+						MainWindow.Instance.AssemblyTreeModel.SelectNodes(state.DecompiledNodes);
 					}
 					else
 					{
 						MainWindow.Instance.NavigateTo(new(state.ViewedUri, null));
 					}
 				}
-				MessageBus.Send(this, new DockWorkspaceActiveTabPageChangedEventArgs());
 			}
 		}
 
 		public void InitializeLayout(DockingManager manager)
 		{
-			var toolPanes = exportProvider.GetExportedValues<ToolPaneModel>("ToolPane").OrderBy(item => item.Title);
+			var panes = exportProvider.GetExportedValues<ToolPaneModel>("ToolPane").OrderBy(item => item.Title);
 
-			this.toolPanes.AddRange(toolPanes);
+			this.toolPanes.AddRange(panes);
 
 			manager.LayoutUpdateStrategy = this;
 			XmlLayoutSerializer serializer = new XmlLayoutSerializer(manager);
diff --git a/ILSpy/ExtensionMethods.cs b/ILSpy/ExtensionMethods.cs
index df6909ab3..39d623fd9 100644
--- a/ILSpy/ExtensionMethods.cs
+++ b/ILSpy/ExtensionMethods.cs
@@ -195,5 +195,21 @@ namespace ICSharpCode.ILSpy
 
 			return true;
 		}
+
+		public static IDisposable PreserveFocus(this IInputElement? inputElement, bool preserve = true)
+		{
+			return new RestoreFocusHelper(inputElement, preserve);
+		}
+
+		private sealed class RestoreFocusHelper(IInputElement? inputElement, bool preserve) : IDisposable
+		{
+			public void Dispose()
+			{
+				if (preserve)
+				{
+					inputElement?.Focus();
+				}
+			}
+		}
 	}
 }
diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs
index b570ba12e..f7cf47367 100644
--- a/ILSpy/Languages/CSharpLanguage.cs
+++ b/ILSpy/Languages/CSharpLanguage.cs
@@ -358,7 +358,7 @@ namespace ICSharpCode.ILSpy
 
 		void AddReferenceWarningMessage(MetadataFile module, ITextOutput output)
 		{
-			var loadedAssembly = MainWindow.Instance.AssemblyTreeModel.CurrentAssemblyList.GetAssemblies().FirstOrDefault(la => la.GetMetadataFileOrNull() == module);
+			var loadedAssembly = MainWindow.Instance.AssemblyTreeModel.AssemblyList.GetAssemblies().FirstOrDefault(la => la.GetMetadataFileOrNull() == module);
 			if (loadedAssembly == null || !loadedAssembly.LoadedAssemblyReferencesInfo.HasErrors)
 				return;
 			string line1 = Properties.Resources.WarningSomeAssemblyReference;
diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs
index 7dd5f5c56..7b1e2b1d6 100644
--- a/ILSpy/MainWindow.xaml.cs
+++ b/ILSpy/MainWindow.xaml.cs
@@ -439,7 +439,7 @@ namespace ICSharpCode.ILSpy
 			base.OnClosing(e);
 			var sessionSettings = SettingsService.Instance.SessionSettings;
 
-			sessionSettings.ActiveAssemblyList = AssemblyTreeModel.CurrentAssemblyList.ListName;
+			sessionSettings.ActiveAssemblyList = AssemblyTreeModel.AssemblyList.ListName;
 			sessionSettings.ActiveTreeViewPath = AssemblyTreeModel.SelectedPath;
 			sessionSettings.ActiveAutoLoadedAssembly = GetAutoLoadedAssemblyNode(AssemblyTreeModel.SelectedItem);
 			sessionSettings.WindowBounds = this.RestoreBounds;
diff --git a/ILSpy/Metadata/CoffHeaderTreeNode.cs b/ILSpy/Metadata/CoffHeaderTreeNode.cs
index 78eca5bf2..36b9c8be8 100644
--- a/ILSpy/Metadata/CoffHeaderTreeNode.cs
+++ b/ILSpy/Metadata/CoffHeaderTreeNode.cs
@@ -28,6 +28,8 @@ using ICSharpCode.ILSpy.TreeNodes;
 using ICSharpCode.ILSpy.ViewModels;
 using ICSharpCode.ILSpyX.Extensions;
 
+using TomsToolbox.Essentials;
+
 namespace ICSharpCode.ILSpy.Metadata
 {
 	class CoffHeaderTreeNode : ILSpyTreeNode
diff --git a/ILSpy/Metadata/OptionalHeaderTreeNode.cs b/ILSpy/Metadata/OptionalHeaderTreeNode.cs
index dc1be30ec..8353ead80 100644
--- a/ILSpy/Metadata/OptionalHeaderTreeNode.cs
+++ b/ILSpy/Metadata/OptionalHeaderTreeNode.cs
@@ -27,6 +27,8 @@ using ICSharpCode.Decompiler.Metadata;
 using ICSharpCode.ILSpy.TreeNodes;
 using ICSharpCode.ILSpyX.Extensions;
 
+using TomsToolbox.Essentials;
+
 namespace ICSharpCode.ILSpy.Metadata
 {
 	class OptionalHeaderTreeNode : ILSpyTreeNode
diff --git a/ILSpy/Search/SearchPane.xaml.cs b/ILSpy/Search/SearchPane.xaml.cs
index 2a5a104d6..454112d5c 100644
--- a/ILSpy/Search/SearchPane.xaml.cs
+++ b/ILSpy/Search/SearchPane.xaml.cs
@@ -249,7 +249,7 @@ namespace ICSharpCode.ILSpy.Search
 			{
 
 				searchProgressBar.IsIndeterminate = true;
-				startedSearch = new(await mainWindow.AssemblyTreeModel.CurrentAssemblyList.GetAllAssemblies(), searchTerm,
+				startedSearch = new(await mainWindow.AssemblyTreeModel.AssemblyList.GetAllAssemblies(), searchTerm,
 					(SearchMode)searchModeComboBox.SelectedIndex, mainWindow.AssemblyTreeModel.CurrentLanguage,
 					SettingsService.Instance.SessionSettings.LanguageSettings.ShowApiLevel);
 				currentSearch = startedSearch;
diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs
index 842fc860f..40fd4ba7c 100644
--- a/ILSpy/TextView/DecompilerTextView.cs
+++ b/ILSpy/TextView/DecompilerTextView.cs
@@ -414,7 +414,7 @@ namespace ICSharpCode.ILSpy.TextView
 			}
 			else if (segment.Reference is EntityReference unresolvedEntity)
 			{
-				var module = unresolvedEntity.ResolveAssembly(MainWindow.Instance.AssemblyTreeModel.CurrentAssemblyList);
+				var module = unresolvedEntity.ResolveAssembly(MainWindow.Instance.AssemblyTreeModel.AssemblyList);
 				if (module == null)
 					return null;
 				var typeSystem = new DecompilerTypeSystem(module,
@@ -474,7 +474,7 @@ namespace ICSharpCode.ILSpy.TextView
 
 			IEntity? ResolveReference(string idString)
 			{
-				return AssemblyListPaneModel.FindEntityInRelevantAssemblies(idString, MainWindow.Instance.AssemblyTreeModel.CurrentAssemblyList.GetAssemblies());
+				return AssemblyListPaneModel.FindEntityInRelevantAssemblies(idString, MainWindow.Instance.AssemblyTreeModel.AssemblyList.GetAssemblies());
 			}
 		}
 
diff --git a/ILSpy/TreeNodes/AssemblyListTreeNode.cs b/ILSpy/TreeNodes/AssemblyListTreeNode.cs
index c7668c1c5..e8a984087 100644
--- a/ILSpy/TreeNodes/AssemblyListTreeNode.cs
+++ b/ILSpy/TreeNodes/AssemblyListTreeNode.cs
@@ -24,6 +24,7 @@ using System.Windows;
 using ICSharpCode.Decompiler;
 using ICSharpCode.Decompiler.Metadata;
 using ICSharpCode.Decompiler.TypeSystem;
+using ICSharpCode.Decompiler.Util;
 using ICSharpCode.ILSpyX;
 using ICSharpCode.ILSpyX.TreeView;
 using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions;
diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs
index ad87b4d41..1c38c4e4c 100644
--- a/ILSpy/TreeNodes/AssemblyTreeNode.cs
+++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs
@@ -712,7 +712,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
 					node.RaisePropertyChanged(nameof(ILSpyTreeNode.IsAutoLoaded));
 				}
 			}
-			MainWindow.Instance.AssemblyTreeModel.CurrentAssemblyList.RefreshSave();
+			MainWindow.Instance.AssemblyTreeModel.AssemblyList.RefreshSave();
 		}
 	}
 
diff --git a/ILSpy/TreeNodes/ILSpyTreeNode.cs b/ILSpy/TreeNodes/ILSpyTreeNode.cs
index 3c319ab54..4c151f4d5 100644
--- a/ILSpy/TreeNodes/ILSpyTreeNode.cs
+++ b/ILSpy/TreeNodes/ILSpyTreeNode.cs
@@ -85,7 +85,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
 			return false;
 		}
 
-		protected internal override void OnChildrenChanged(NotifyCollectionChangedEventArgs e)
+		public override void OnChildrenChanged(NotifyCollectionChangedEventArgs e)
 		{
 			if (e.NewItems != null)
 			{
diff --git a/ILSpy/Util/MessageBus.cs b/ILSpy/Util/MessageBus.cs
index 40d8743b8..0ba600ce8 100644
--- a/ILSpy/Util/MessageBus.cs
+++ b/ILSpy/Util/MessageBus.cs
@@ -22,16 +22,16 @@ namespace ICSharpCode.ILSpy.Util
 	public static class MessageBus<T>
 		where T : EventArgs
 	{
-		private static readonly WeakEventSource<T> Subscriptions = new();
+		private static readonly WeakEventSource<T> subscriptions = new();
 
 		public static event EventHandler<T> Subscribers {
-			add => Subscriptions.Subscribe(value);
-			remove => Subscriptions.Unsubscribe(value);
+			add => subscriptions.Subscribe(value);
+			remove => subscriptions.Unsubscribe(value);
 		}
 
 		public static void Send(object sender, T e)
 		{
-			Subscriptions.Raise(sender, e);
+			subscriptions.Raise(sender, e);
 		}
 	}
 
@@ -56,8 +56,6 @@ namespace ICSharpCode.ILSpy.Util
 
 	public class SessionSettingsChangedEventArgs(PropertyChangedEventArgs e) : WrappedEventArgs<PropertyChangedEventArgs>(e);
 
-	public class DockWorkspaceActiveTabPageChangedEventArgs : EventArgs;
-
 	public class NavigateToReferenceEventArgs(object reference, bool inNewTabPage = false) : EventArgs
 	{
 		public object Reference { get; } = reference;
diff --git a/ILSpy/Views/OpenFromGacDialog.xaml.cs b/ILSpy/Views/OpenFromGacDialog.xaml.cs
index 5189be034..24b9f7b2b 100644
--- a/ILSpy/Views/OpenFromGacDialog.xaml.cs
+++ b/ILSpy/Views/OpenFromGacDialog.xaml.cs
@@ -31,6 +31,8 @@ using ICSharpCode.Decompiler.Metadata;
 using ICSharpCode.ILSpy.Controls;
 using ICSharpCode.ILSpyX.Extensions;
 
+using TomsToolbox.Essentials;
+
 namespace ICSharpCode.ILSpy
 {
 	/// <summary>
diff --git a/TestPlugin/MainMenuCommand.cs b/TestPlugin/MainMenuCommand.cs
index f2909e15b..8c28e7fe1 100644
--- a/TestPlugin/MainMenuCommand.cs
+++ b/TestPlugin/MainMenuCommand.cs
@@ -23,7 +23,7 @@ namespace TestPlugin
 	{
 		public override void Execute(object parameter)
 		{
-			foreach (var loadedAssembly in MainWindow.Instance.AssemblyTreeModel.CurrentAssemblyList.GetAssemblies())
+			foreach (var loadedAssembly in MainWindow.Instance.AssemblyTreeModel.AssemblyList.GetAssemblies())
 			{
 				loadedAssembly.AssemblyList.Unload(loadedAssembly);
 			}