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); }