diff --git a/ILSpy/Analyzers/AnalyzerTreeView.cs b/ILSpy/Analyzers/AnalyzerTreeView.cs index b81763990..261e52b18 100644 --- a/ILSpy/Analyzers/AnalyzerTreeView.cs +++ b/ILSpy/Analyzers/AnalyzerTreeView.cs @@ -35,6 +35,8 @@ namespace ICSharpCode.ILSpy.Analyzers /// public class AnalyzerTreeView : SharpTreeView { + FilterSettings filterSettings; + public AnalyzerTreeView() { this.ShowRoot = false; @@ -42,7 +44,21 @@ namespace ICSharpCode.ILSpy.Analyzers this.BorderThickness = new Thickness(0); ContextMenuProvider.Add(this); MainWindow.Instance.CurrentAssemblyListChanged += MainWindow_Instance_CurrentAssemblyListChanged; - MainWindow.Instance.SessionSettings.FilterSettings.PropertyChanged += FilterSettings_PropertyChanged; + DockWorkspace.Instance.PropertyChanged += DockWorkspace_PropertyChanged; + filterSettings = MainWindow.Instance.SessionSettings.FilterSettings; + filterSettings.PropertyChanged += FilterSettings_PropertyChanged; + } + + private void DockWorkspace_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + switch (e.PropertyName) + { + case nameof(DockWorkspace.Instance.ActiveTabPage): + filterSettings.PropertyChanged -= FilterSettings_PropertyChanged; + filterSettings = DockWorkspace.Instance.ActiveTabPage.FilterSettings; + filterSettings.PropertyChanged += FilterSettings_PropertyChanged; + break; + } } private void FilterSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) diff --git a/ILSpy/Docking/DockWorkspace.cs b/ILSpy/Docking/DockWorkspace.cs index ede66930e..2b1241e65 100644 --- a/ILSpy/Docking/DockWorkspace.cs +++ b/ILSpy/Docking/DockWorkspace.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Collections.Specialized; using System.ComponentModel; using System.ComponentModel.Composition; using System.Linq; @@ -45,14 +46,46 @@ namespace ICSharpCode.ILSpy.Docking public event PropertyChangedEventHandler PropertyChanged; - public static DockWorkspace Instance { get; } = new DockWorkspace(); + public static DockWorkspace Instance { get; private set; } - private DockWorkspace() + internal DockWorkspace(MainWindow parent) { + Instance = this; this.TabPages.CollectionChanged += Documents_CollectionChanged; + parent.CurrentAssemblyListChanged += MainWindow_Instance_CurrentAssemblyListChanged; } - private void Documents_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + private void MainWindow_Instance_CurrentAssemblyListChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (e.OldItems == null) + { + return; + } + foreach (var tab in TabPages.ToArray()) + { + var state = tab.GetState(); + if (state == null || state.DecompiledNodes == null) + { + continue; + } + bool found = false; + foreach (var node in state.DecompiledNodes) + { + var assemblyNode = node.Ancestors().OfType().LastOrDefault(); + if (assemblyNode != null && !e.OldItems.Contains(assemblyNode.LoadedAssembly)) + { + found = true; + break; + } + } + if (!found && TabPages.Count > 1) + { + TabPages.Remove(tab); + } + } + } + + private void Documents_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { var collection = (PaneCollection)sender; bool canClose = collection.Count > 1; @@ -94,8 +127,6 @@ namespace ICSharpCode.ILSpy.Docking if (_activeTabPage != value) { _activeTabPage = value; - this.sessionSettings.FilterSettings.Language = value.Language; - this.sessionSettings.FilterSettings.LanguageVersion = value.LanguageVersion; var state = value.GetState(); if (state != null) { @@ -173,23 +204,6 @@ namespace ICSharpCode.ILSpy.Docking internal void LoadSettings(SessionSettings sessionSettings) { this.sessionSettings = sessionSettings; - sessionSettings.FilterSettings.PropertyChanged += FilterSettings_PropertyChanged; - } - - private void FilterSettings_PropertyChanged(object sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == "Language") - { - ActiveTabPage.Language = sessionSettings.FilterSettings.Language; - if (sessionSettings.FilterSettings.Language.HasLanguageVersions) - { - sessionSettings.FilterSettings.LanguageVersion = ActiveTabPage.LanguageVersion; - } - } - else if (e.PropertyName == "LanguageVersion") - { - ActiveTabPage.LanguageVersion = sessionSettings.FilterSettings.LanguageVersion; - } } internal void CloseAllTabs() diff --git a/ILSpy/FilterSettings.cs b/ILSpy/FilterSettings.cs index 11930783e..cc0aa4b05 100644 --- a/ILSpy/FilterSettings.cs +++ b/ILSpy/FilterSettings.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; @@ -34,6 +35,13 @@ namespace ICSharpCode.ILSpy /// public class FilterSettings : INotifyPropertyChanged { + /// + /// This dictionary is necessary to remember language versions across language changes. For example, + /// the user first select C# 10, then switches to IL, then switches back to C#. After that we must be + /// able to restore the original selection (i.e., C# 10). + /// + private readonly Dictionary languageVersionHistory = new Dictionary(); + public FilterSettings(XElement element) { this.ShowApiLevel = (ApiVisibility?)(int?)element.Element("ShowAPILevel") ?? ApiVisibility.PublicAndInternal; @@ -146,8 +154,27 @@ namespace ICSharpCode.ILSpy set { if (language != value) { + if (language != null && language.HasLanguageVersions) + { + languageVersionHistory[language] = languageVersion; + } language = value; OnPropertyChanged(); + if (language.HasLanguageVersions) + { + if (languageVersionHistory.TryGetValue(value, out var version)) + { + LanguageVersion = version; + } + else + { + LanguageVersion = Language.LanguageVersions.Last(); + } + } + else + { + LanguageVersion = default; + } } } } @@ -167,6 +194,10 @@ namespace ICSharpCode.ILSpy if (languageVersion != value) { languageVersion = value; + if (language.HasLanguageVersions) + { + languageVersionHistory[language] = languageVersion; + } OnPropertyChanged(); } } diff --git a/ILSpy/MainWindow.xaml b/ILSpy/MainWindow.xaml index 8a20d45cb..8fbdd7d58 100644 --- a/ILSpy/MainWindow.xaml +++ b/ILSpy/MainWindow.xaml @@ -19,7 +19,7 @@ xmlns:styles="urn:TomsToolbox.Wpf.Styles" xmlns:b="http://schemas.microsoft.com/xaml/behaviors" xmlns:themes="clr-namespace:ICSharpCode.ILSpy.Themes" - d:DataContext="{d:DesignInstance local:MainWindowDataContext}" + d:DataContext="{d:DesignInstance local:MainWindowViewModel}" > @@ -103,9 +103,9 @@ - - - + + + @@ -156,25 +156,25 @@ - + - + - + + SelectedItem="{Binding Workspace.ActiveTabPage.FilterSettings.Language}"/> + SelectedItem="{Binding Workspace.ActiveTabPage.FilterSettings.LanguageVersion, UpdateSourceTrigger=PropertyChanged}"/> diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 7f1c9070d..db0e5b887 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -32,7 +32,6 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Interop; using System.Windows.Media; -using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Threading; @@ -55,13 +54,6 @@ using Microsoft.Win32; namespace ICSharpCode.ILSpy { - class MainWindowDataContext - { - public DockWorkspace Workspace { get; set; } - public SessionSettings SessionSettings { get; set; } - public AssemblyListManager AssemblyListManager { get; set; } - } - /// /// The main window of the application. /// @@ -70,7 +62,8 @@ namespace ICSharpCode.ILSpy bool refreshInProgress, changingActiveTab; readonly NavigationHistory history = new NavigationHistory(); ILSpySettings spySettingsForMainWindow_Loaded; - internal SessionSettings sessionSettings; + SessionSettings sessionSettings; + FilterSettings filterSettings; AssemblyList assemblyList; AssemblyListTreeNode assemblyListTreeNode; @@ -115,8 +108,8 @@ namespace ICSharpCode.ILSpy // Make sure Images are initialized on the UI thread. this.Icon = Images.ILSpyIcon; - this.DataContext = new MainWindowDataContext { - Workspace = DockWorkspace.Instance, + this.DataContext = new MainWindowViewModel { + Workspace = new DockWorkspace(this), SessionSettings = sessionSettings, AssemblyListManager = AssemblyListManager }; @@ -130,8 +123,10 @@ namespace ICSharpCode.ILSpy InitializeComponent(); InitToolPanes(); DockWorkspace.Instance.InitializeLayout(DockManager); - sessionSettings.FilterSettings.PropertyChanged += filterSettings_PropertyChanged; sessionSettings.PropertyChanged += SessionSettings_PropertyChanged; + filterSettings = sessionSettings.FilterSettings; + filterSettings.PropertyChanged += filterSettings_PropertyChanged; + DockWorkspace.Instance.PropertyChanged += DockWorkspace_PropertyChanged; InitMainMenu(); InitToolbar(); ContextMenuProvider.Add(AssemblyTreeView); @@ -139,6 +134,18 @@ namespace ICSharpCode.ILSpy this.Loaded += MainWindow_Loaded; } + private void DockWorkspace_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + switch (e.PropertyName) + { + case nameof(DockWorkspace.Instance.ActiveTabPage): + filterSettings.PropertyChanged -= filterSettings_PropertyChanged; + filterSettings = DockWorkspace.Instance.ActiveTabPage.FilterSettings; + filterSettings.PropertyChanged += filterSettings_PropertyChanged; + break; + } + } + private void SessionSettings_PropertyChanged(object sender, PropertyChangedEventArgs e) { switch (e.PropertyName) @@ -406,7 +413,7 @@ namespace ICSharpCode.ILSpy { LoadAssemblies(args.AssembliesToLoad, commandLineLoadedAssemblies, focusNode: false); if (args.Language != null) - sessionSettings.FilterSettings.Language = Languages.GetLanguage(args.Language); + filterSettings.Language = Languages.GetLanguage(args.Language); return true; } @@ -597,8 +604,7 @@ namespace ICSharpCode.ILSpy void MainWindow_Loaded(object sender, RoutedEventArgs e) { DockWorkspace.Instance.TabPages.Add(new TabPageModel() { - Language = CurrentLanguage, - LanguageVersion = CurrentLanguageVersion + FilterSettings = filterSettings.Clone() }); DockWorkspace.Instance.ActiveTabPage = DockWorkspace.Instance.TabPages.First(); @@ -770,7 +776,7 @@ namespace ICSharpCode.ILSpy assemblyList.CollectionChanged += assemblyList_Assemblies_CollectionChanged; assemblyListTreeNode = new AssemblyListTreeNode(assemblyList); - assemblyListTreeNode.FilterSettings = sessionSettings.FilterSettings.Clone(); + assemblyListTreeNode.FilterSettings = filterSettings.Clone(); assemblyListTreeNode.Select = x => SelectNode(x, inNewTabPage: false); AssemblyTreeView.Root = assemblyListTreeNode; @@ -824,7 +830,6 @@ namespace ICSharpCode.ILSpy void filterSettings_PropertyChanged(object sender, PropertyChangedEventArgs e) { - RefreshTreeView(); RefreshTreeViewFilter(); if (e.PropertyName == "Language" || e.PropertyName == "LanguageVersion") { @@ -838,7 +843,7 @@ namespace ICSharpCode.ILSpy // Thus, the main window will use one mutable instance (for data-binding), and assign a new clone to the ILSpyTreeNodes whenever the main // mutable instance changes. if (assemblyListTreeNode != null) - assemblyListTreeNode.FilterSettings = sessionSettings.FilterSettings.Clone(); + assemblyListTreeNode.FilterSettings = DockWorkspace.Instance.ActiveTabPage.FilterSettings.Clone(); } internal AssemblyListTreeNode AssemblyListTreeNode { @@ -867,8 +872,7 @@ namespace ICSharpCode.ILSpy { DockWorkspace.Instance.TabPages.Add( new TabPageModel() { - Language = CurrentLanguage, - LanguageVersion = CurrentLanguageVersion + FilterSettings = filterSettings.Clone() }); DockWorkspace.Instance.ActiveTabPage = DockWorkspace.Instance.TabPages.Last(); AssemblyTreeView.SelectedItem = null; @@ -914,8 +918,7 @@ namespace ICSharpCode.ILSpy { DockWorkspace.Instance.TabPages.Add( new TabPageModel() { - Language = CurrentLanguage, - LanguageVersion = CurrentLanguageVersion + FilterSettings = filterSettings.Clone() }); DockWorkspace.Instance.ActiveTabPage = DockWorkspace.Instance.TabPages.Last(); } @@ -1173,11 +1176,6 @@ namespace ICSharpCode.ILSpy } void RefreshCommandExecuted(object sender, ExecutedRoutedEventArgs e) - { - RefreshTreeView(); - } - - void RefreshTreeView() { try { @@ -1206,7 +1204,10 @@ namespace ICSharpCode.ILSpy { state = DockWorkspace.Instance.ActiveTabPage.GetState() as DecompilerTextViewState; } - DecompileSelectedNodes(state); + if (!changingActiveTab) + { + DecompileSelectedNodes(state); + } SelectionChanged?.Invoke(sender, e); } @@ -1274,8 +1275,10 @@ namespace ICSharpCode.ILSpy } } - public Language CurrentLanguage => sessionSettings.FilterSettings.Language; - public LanguageVersion CurrentLanguageVersion => sessionSettings.FilterSettings.LanguageVersion; + public Language CurrentLanguage => DockWorkspace.Instance.ActiveTabPage.FilterSettings.Language; + public LanguageVersion CurrentLanguageVersion => DockWorkspace.Instance.ActiveTabPage.FilterSettings.LanguageVersion; + + public bool SupportsLanguageSwitching => DockWorkspace.Instance.ActiveTabPage.SupportsLanguageSwitching; public event SelectionChangedEventHandler SelectionChanged; @@ -1347,8 +1350,7 @@ namespace ICSharpCode.ILSpy { DockWorkspace.Instance.TabPages.Add( new TabPageModel() { - Language = CurrentLanguage, - LanguageVersion = CurrentLanguageVersion + FilterSettings = filterSettings.Clone() }); DockWorkspace.Instance.ActiveTabPage = DockWorkspace.Instance.TabPages.Last(); } @@ -1413,6 +1415,7 @@ namespace ICSharpCode.ILSpy sessionSettings.ActiveAutoLoadedAssembly = GetAutoLoadedAssemblyNode(AssemblyTreeView.SelectedItem as SharpTreeNode); sessionSettings.WindowBounds = this.RestoreBounds; sessionSettings.DockLayout.Serialize(new XmlLayoutSerializer(DockManager)); + sessionSettings.FilterSettings = DockWorkspace.Instance.ActiveTabPage.FilterSettings.Clone(); sessionSettings.Save(); } diff --git a/ILSpy/MainWindowViewModel.cs b/ILSpy/MainWindowViewModel.cs new file mode 100644 index 000000000..6568e18db --- /dev/null +++ b/ILSpy/MainWindowViewModel.cs @@ -0,0 +1,30 @@ +// Copyright (c) 2021 Siegfried Pammer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using ICSharpCode.ILSpy.Docking; +using ICSharpCode.ILSpy.ViewModels; + +namespace ICSharpCode.ILSpy +{ + class MainWindowViewModel + { + public DockWorkspace Workspace { get; set; } + public SessionSettings SessionSettings { get; set; } + public AssemblyListManager AssemblyListManager { get; set; } + } +} diff --git a/ILSpy/Search/SearchPane.cs b/ILSpy/Search/SearchPane.cs index 5c446c9bf..cb63a675d 100644 --- a/ILSpy/Search/SearchPane.cs +++ b/ILSpy/Search/SearchPane.cs @@ -50,6 +50,7 @@ namespace ICSharpCode.ILSpy RunningSearch currentSearch; bool runSearchOnNextShow; IComparer resultsComparer; + FilterSettings filterSettings; public static readonly DependencyProperty ResultsProperty = DependencyProperty.Register("Results", typeof(ObservableCollection), typeof(SearchPane), @@ -76,13 +77,27 @@ namespace ICSharpCode.ILSpy ContextMenuProvider.Add(listBox); MainWindow.Instance.CurrentAssemblyListChanged += MainWindow_Instance_CurrentAssemblyListChanged; - MainWindow.Instance.SessionSettings.FilterSettings.PropertyChanged += FilterSettings_PropertyChanged; + DockWorkspace.Instance.PropertyChanged += DockWorkspace_PropertyChanged; + filterSettings = MainWindow.Instance.SessionSettings.FilterSettings; + filterSettings.PropertyChanged += FilterSettings_PropertyChanged; CompositionTarget.Rendering += UpdateResults; // This starts empty search right away, so do at the end (we're still in ctor) searchModeComboBox.SelectedIndex = (int)MainWindow.Instance.SessionSettings.SelectedSearchMode; } + private void DockWorkspace_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + switch (e.PropertyName) + { + case nameof(DockWorkspace.Instance.ActiveTabPage): + filterSettings.PropertyChanged -= FilterSettings_PropertyChanged; + filterSettings = DockWorkspace.Instance.ActiveTabPage.FilterSettings; + filterSettings.PropertyChanged += FilterSettings_PropertyChanged; + break; + } + } + void MainWindow_Instance_CurrentAssemblyListChanged(object sender, NotifyCollectionChangedEventArgs e) { if (IsVisible) diff --git a/ILSpy/SessionSettings.cs b/ILSpy/SessionSettings.cs index ee1bcbf58..6fa003ff3 100644 --- a/ILSpy/SessionSettings.cs +++ b/ILSpy/SessionSettings.cs @@ -76,7 +76,7 @@ namespace ICSharpCode.ILSpy PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } - public FilterSettings FilterSettings { get; private set; } + public FilterSettings FilterSettings { get; internal set; } public SearchMode SelectedSearchMode { get; set; } public bool IsDarkMode { diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index a6fbac1a8..ffc9ef303 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -152,7 +152,7 @@ namespace ICSharpCode.ILSpy.TextView { if (this.DataContext is PaneModel model) { - model.Title = currentTitle ?? ILSpy.Properties.Resources.NewTab; + model.Title = currentTitle ?? ILSpy.Properties.Resources.Decompiling; } } @@ -665,8 +665,8 @@ namespace ICSharpCode.ILSpy.TextView textOutput.Title = string.Join(", ", nodes.Select(n => n.Text)); } - ShowOutput(textOutput, highlighting); decompiledNodes = nodes; + ShowOutput(textOutput, highlighting); } /// @@ -815,12 +815,12 @@ namespace ICSharpCode.ILSpy.TextView return RunWithCancellation( delegate (CancellationToken ct) { // creation of the background task context.Options.CancellationToken = ct; + decompiledNodes = context.TreeNodes; return DecompileAsync(context, outputLengthLimit); }) .Then( delegate (AvalonEditTextOutput textOutput) { // handling the result ShowOutput(textOutput, context.Language.SyntaxHighlighting, context.Options.TextViewState); - decompiledNodes = context.TreeNodes; }) .Catch(exception => { textEditor.SyntaxHighlighting = null; @@ -835,7 +835,6 @@ namespace ICSharpCode.ILSpy.TextView output.WriteLine(exception.ToString()); } ShowOutput(output); - decompiledNodes = context.TreeNodes; }); } diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs index 19b4df1b8..da10af18c 100644 --- a/ILSpy/TreeNodes/AssemblyTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs @@ -200,7 +200,7 @@ namespace ICSharpCode.ILSpy.TreeNodes void LoadChildrenForPEFile(PEFile module) { - typeSystem = LoadedAssembly.GetTypeSystemOrNull(DecompilerTypeSystem.GetOptions(new DecompilationOptions().DecompilerSettings)); + typeSystem = LoadedAssembly.GetTypeSystemOrNull(); var assembly = (MetadataModule)typeSystem.MainModule; this.Children.Add(new Metadata.MetadataTreeNode(module, this)); Decompiler.DebugInfo.IDebugInfoProvider debugInfo = LoadedAssembly.GetDebugInfoOrNull(); diff --git a/ILSpy/TreeNodes/EventTreeNode.cs b/ILSpy/TreeNodes/EventTreeNode.cs index 38ad76f5b..b9cce0968 100644 --- a/ILSpy/TreeNodes/EventTreeNode.cs +++ b/ILSpy/TreeNodes/EventTreeNode.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Reflection.Metadata; using System.Windows.Media; using ICSharpCode.Decompiler; @@ -45,14 +46,21 @@ namespace ICSharpCode.ILSpy.TreeNodes public IEvent EventDefinition { get; } - public override object Text => GetText(EventDefinition, this.Language) + EventDefinition.MetadataToken.ToSuffixString(); + public override object Text => GetText(GetEventDefinition(), this.Language) + EventDefinition.MetadataToken.ToSuffixString(); + + private IEvent GetEventDefinition() + { + return ((MetadataModule)EventDefinition.ParentModule.PEFile + ?.GetTypeSystemWithCurrentOptionsOrNull() + ?.MainModule)?.GetDefinition((EventDefinitionHandle)EventDefinition.MetadataToken) ?? EventDefinition; + } public static object GetText(IEvent ev, Language language) { return language.EventToString(ev, false, false, false); } - public override object Icon => GetIcon(EventDefinition); + public override object Icon => GetIcon(GetEventDefinition()); public static ImageSource GetIcon(IEvent @event) { @@ -76,7 +84,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public override bool IsPublicAPI { get { - switch (EventDefinition.Accessibility) + switch (GetEventDefinition().Accessibility) { case Accessibility.Public: case Accessibility.ProtectedOrInternal: diff --git a/ILSpy/TreeNodes/FieldTreeNode.cs b/ILSpy/TreeNodes/FieldTreeNode.cs index a997c2547..fab2c6ae4 100644 --- a/ILSpy/TreeNodes/FieldTreeNode.cs +++ b/ILSpy/TreeNodes/FieldTreeNode.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Reflection.Metadata; using System.Windows.Media; using ICSharpCode.Decompiler; @@ -37,14 +38,21 @@ namespace ICSharpCode.ILSpy.TreeNodes this.FieldDefinition = field ?? throw new ArgumentNullException(nameof(field)); } - public override object Text => GetText(FieldDefinition, Language) + FieldDefinition.MetadataToken.ToSuffixString(); + public override object Text => GetText(GetFieldDefinition(), Language) + FieldDefinition.MetadataToken.ToSuffixString(); + + private IField GetFieldDefinition() + { + return ((MetadataModule)FieldDefinition.ParentModule.PEFile + ?.GetTypeSystemWithCurrentOptionsOrNull() + ?.MainModule)?.GetDefinition((FieldDefinitionHandle)FieldDefinition.MetadataToken) ?? FieldDefinition; + } public static object GetText(IField field, Language language) { return language.FieldToString(field, includeDeclaringTypeName: false, includeNamespace: false, includeNamespaceOfDeclaringTypeName: false); } - public override object Icon => GetIcon(FieldDefinition); + public override object Icon => GetIcon(GetFieldDefinition()); public static ImageSource GetIcon(IField field) { @@ -77,7 +85,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public override bool IsPublicAPI { get { - switch (FieldDefinition.Accessibility) + switch (GetFieldDefinition().Accessibility) { case Accessibility.Public: case Accessibility.Protected: diff --git a/ILSpy/TreeNodes/MethodTreeNode.cs b/ILSpy/TreeNodes/MethodTreeNode.cs index 474639b94..408e5a36e 100644 --- a/ILSpy/TreeNodes/MethodTreeNode.cs +++ b/ILSpy/TreeNodes/MethodTreeNode.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Reflection.Metadata; using System.Windows.Media; using ICSharpCode.Decompiler; @@ -37,14 +38,21 @@ namespace ICSharpCode.ILSpy.TreeNodes this.MethodDefinition = method ?? throw new ArgumentNullException(nameof(method)); } - public override object Text => GetText(MethodDefinition, Language) + MethodDefinition.MetadataToken.ToSuffixString(); + public override object Text => GetText(GetMethodDefinition(), Language) + MethodDefinition.MetadataToken.ToSuffixString(); + + private IMethod GetMethodDefinition() + { + return ((MetadataModule)MethodDefinition.ParentModule.PEFile + ?.GetTypeSystemWithCurrentOptionsOrNull() + ?.MainModule)?.GetDefinition((MethodDefinitionHandle)MethodDefinition.MetadataToken) ?? MethodDefinition; + } public static object GetText(IMethod method, Language language) { return language.MethodToString(method, false, false, false); } - public override object Icon => GetIcon(MethodDefinition); + public override object Icon => GetIcon(GetMethodDefinition()); public static ImageSource GetIcon(IMethod method) { @@ -102,7 +110,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public override bool IsPublicAPI { get { - switch (MethodDefinition.Accessibility) + switch (GetMethodDefinition().Accessibility) { case Accessibility.Public: case Accessibility.Protected: diff --git a/ILSpy/TreeNodes/PropertyTreeNode.cs b/ILSpy/TreeNodes/PropertyTreeNode.cs index 5dec47290..e8e2e149d 100644 --- a/ILSpy/TreeNodes/PropertyTreeNode.cs +++ b/ILSpy/TreeNodes/PropertyTreeNode.cs @@ -17,14 +17,10 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Reflection; using System.Reflection.Metadata; using System.Windows.Media; using ICSharpCode.Decompiler; -using ICSharpCode.Decompiler.Metadata; - -using SRM = System.Reflection.Metadata; namespace ICSharpCode.ILSpy.TreeNodes { @@ -52,14 +48,21 @@ namespace ICSharpCode.ILSpy.TreeNodes public IProperty PropertyDefinition { get; } - public override object Text => GetText(PropertyDefinition, Language) + PropertyDefinition.MetadataToken.ToSuffixString(); + public override object Text => GetText(GetPropertyDefinition(), Language) + PropertyDefinition.MetadataToken.ToSuffixString(); + + private IProperty GetPropertyDefinition() + { + return ((MetadataModule)PropertyDefinition.ParentModule.PEFile + ?.GetTypeSystemWithCurrentOptionsOrNull() + ?.MainModule)?.GetDefinition((PropertyDefinitionHandle)PropertyDefinition.MetadataToken) ?? PropertyDefinition; + } public static object GetText(IProperty property, Language language) { return language.PropertyToString(property, false, false, false); } - public override object Icon => GetIcon(PropertyDefinition); + public override object Icon => GetIcon(GetPropertyDefinition()); public static ImageSource GetIcon(IProperty property) { @@ -84,7 +87,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public override bool IsPublicAPI { get { - switch (PropertyDefinition.Accessibility) + switch (GetPropertyDefinition().Accessibility) { case Accessibility.Public: case Accessibility.ProtectedOrInternal: diff --git a/ILSpy/TreeNodes/TypeTreeNode.cs b/ILSpy/TreeNodes/TypeTreeNode.cs index 92739230e..3cb5ca3a4 100644 --- a/ILSpy/TreeNodes/TypeTreeNode.cs +++ b/ILSpy/TreeNodes/TypeTreeNode.cs @@ -41,12 +41,20 @@ namespace ICSharpCode.ILSpy.TreeNodes public AssemblyTreeNode ParentAssemblyNode { get; } - public override object Text => this.Language.TypeToString(TypeDefinition, includeNamespace: false) + public override object Text => this.Language.TypeToString(GetTypeDefinition(), includeNamespace: false) + TypeDefinition.MetadataToken.ToSuffixString(); + private ITypeDefinition GetTypeDefinition() + { + return ((MetadataModule)ParentAssemblyNode.LoadedAssembly + .GetPEFileOrNull() + ?.GetTypeSystemWithCurrentOptionsOrNull() + ?.MainModule).GetDefinition((SRM.TypeDefinitionHandle)TypeDefinition.MetadataToken); + } + public override bool IsPublicAPI { get { - switch (TypeDefinition.Accessibility) + switch (GetTypeDefinition().Accessibility) { case Accessibility.Public: case Accessibility.Protected: @@ -120,7 +128,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) { - language.DecompileType(TypeDefinition, output, options); + language.DecompileType(GetTypeDefinition(), output, options); } public override object Icon => GetIcon(TypeDefinition); diff --git a/ILSpy/ViewModels/ManageAssemblyListsViewModel.cs b/ILSpy/ViewModels/ManageAssemblyListsViewModel.cs index f6ff717a5..e1db19ac1 100644 --- a/ILSpy/ViewModels/ManageAssemblyListsViewModel.cs +++ b/ILSpy/ViewModels/ManageAssemblyListsViewModel.cs @@ -191,9 +191,9 @@ namespace ICSharpCode.ILSpy.ViewModels if (manager.AssemblyLists.Count > 0) { SelectedAssemblyList = manager.AssemblyLists[Math.Max(0, index - 1)]; - if (MainWindow.Instance.sessionSettings.ActiveAssemblyList == assemblyList) + if (MainWindow.Instance.SessionSettings.ActiveAssemblyList == assemblyList) { - MainWindow.Instance.sessionSettings.ActiveAssemblyList = SelectedAssemblyList; + MainWindow.Instance.SessionSettings.ActiveAssemblyList = SelectedAssemblyList; } } } @@ -234,9 +234,9 @@ namespace ICSharpCode.ILSpy.ViewModels string assemblyList = SelectedAssemblyList; SelectedAssemblyList = dlg.ListName; manager.RenameList(assemblyList, dlg.ListName); - if (MainWindow.Instance.sessionSettings.ActiveAssemblyList == assemblyList) + if (MainWindow.Instance.SessionSettings.ActiveAssemblyList == assemblyList) { - MainWindow.Instance.sessionSettings.ActiveAssemblyList = manager.AssemblyLists[manager.AssemblyLists.Count - 1]; + MainWindow.Instance.SessionSettings.ActiveAssemblyList = manager.AssemblyLists[manager.AssemblyLists.Count - 1]; } } } @@ -372,7 +372,7 @@ namespace ICSharpCode.ILSpy.ViewModels private void ExecuteSelectAssemblyList() { - MainWindow.Instance.sessionSettings.ActiveAssemblyList = SelectedAssemblyList; + MainWindow.Instance.SessionSettings.ActiveAssemblyList = SelectedAssemblyList; this.parent.Close(); } } diff --git a/ILSpy/ViewModels/TabPageModel.cs b/ILSpy/ViewModels/TabPageModel.cs index f4c42c23d..91903f678 100644 --- a/ILSpy/ViewModels/TabPageModel.cs +++ b/ILSpy/ViewModels/TabPageModel.cs @@ -27,61 +27,36 @@ namespace ICSharpCode.ILSpy.ViewModels { public class TabPageModel : PaneModel { - private readonly Dictionary languageVersionHistory = new Dictionary(); - public TabPageModel() { this.Title = Properties.Resources.NewTab; } - private Language language; - public Language Language { - get => language; + private FilterSettings filterSettings; + + public FilterSettings FilterSettings { + get => filterSettings; set { - if (language != value) + if (filterSettings != value) { - if (language != null && language.HasLanguageVersions) - { - languageVersionHistory[language] = languageVersion; - } - language = value; - RaisePropertyChanged(nameof(Language)); - if (language.HasLanguageVersions) - { - if (languageVersionHistory.TryGetValue(value, out var version)) - { - LanguageVersion = version; - } - else - { - LanguageVersion = Language.LanguageVersions.Last(); - } - } - else - { - LanguageVersion = default; - } + filterSettings = value; + RaisePropertyChanged(nameof(FilterSettings)); } } } - private LanguageVersion languageVersion; + public Language Language { + get => filterSettings.Language; + set => filterSettings.Language = value; + } + public LanguageVersion LanguageVersion { - get => languageVersion; - set { - if (languageVersion != value) - { - languageVersion = value; - if (language.HasLanguageVersions) - { - languageVersionHistory[language] = languageVersion; - } - RaisePropertyChanged(nameof(LanguageVersion)); - } - } + get => filterSettings.LanguageVersion; + set => filterSettings.LanguageVersion = value; } private bool supportsLanguageSwitching = true; + public bool SupportsLanguageSwitching { get => supportsLanguageSwitching; set { @@ -94,6 +69,7 @@ namespace ICSharpCode.ILSpy.ViewModels } private object content; + public object Content { get => content; set { @@ -120,6 +96,7 @@ namespace ICSharpCode.ILSpy.ViewModels textView = new DecompilerTextView(); tabPage.Content = textView; } + tabPage.Title = Properties.Resources.Decompiling; return action(textView); } @@ -130,6 +107,7 @@ namespace ICSharpCode.ILSpy.ViewModels textView = new DecompilerTextView(); tabPage.Content = textView; } + tabPage.Title = Properties.Resources.Decompiling; return action(textView); } @@ -140,6 +118,7 @@ namespace ICSharpCode.ILSpy.ViewModels textView = new DecompilerTextView(); tabPage.Content = textView; } + tabPage.Title = Properties.Resources.Decompiling; action(textView); } } diff --git a/ILSpy/Views/DebugSteps.xaml.cs b/ILSpy/Views/DebugSteps.xaml.cs index d04ce4ebd..2b46753dd 100644 --- a/ILSpy/Views/DebugSteps.xaml.cs +++ b/ILSpy/Views/DebugSteps.xaml.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Input; @@ -22,13 +23,16 @@ namespace ICSharpCode.ILSpy #if DEBUG ILAstLanguage language; #endif + FilterSettings filterSettings; public DebugSteps() { InitializeComponent(); #if DEBUG - MainWindow.Instance.SessionSettings.FilterSettings.PropertyChanged += FilterSettings_PropertyChanged; + DockWorkspace.Instance.PropertyChanged += DockWorkspace_PropertyChanged; + this.filterSettings = MainWindow.Instance.SessionSettings.FilterSettings; + filterSettings.PropertyChanged += FilterSettings_PropertyChanged; MainWindow.Instance.SelectionChanged += SelectionChanged; writingOptions.PropertyChanged += WritingOptions_PropertyChanged; @@ -41,6 +45,18 @@ namespace ICSharpCode.ILSpy #endif } + private void DockWorkspace_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + switch (e.PropertyName) + { + case nameof(DockWorkspace.Instance.ActiveTabPage): + filterSettings.PropertyChanged -= FilterSettings_PropertyChanged; + filterSettings = DockWorkspace.Instance.ActiveTabPage.FilterSettings; + filterSettings.PropertyChanged += FilterSettings_PropertyChanged; + break; + } + } + private void WritingOptions_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { DecompileAsync(lastSelectedStep);