From ecda21f7f978b13b067ac33bcd9f64332002f91c Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 29 Feb 2020 12:27:35 +0100 Subject: [PATCH] Fix #1932: Add ExportToolPaneAttribute and reimplement ShowInBottomPane and ShowInTopPane. --- ILSpy/Analyzers/AnalyzerTreeView.cs | 9 +- ILSpy/Commands/DecompileInNewViewCommand.cs | 2 +- ILSpy/Commands/ExportCommandAttribute.cs | 20 +++- ILSpy/Commands/ShowDebugSteps.cs | 2 +- ILSpy/Commands/SortAssemblyListCommand.cs | 6 +- ILSpy/Docking/DockWorkspace.cs | 93 +++++++++++------ ILSpy/ILSpy.csproj | 2 +- ILSpy/IPane.cs | 26 ----- ILSpy/Languages/ILAstLanguage.cs | 2 +- ILSpy/MainWindow.xaml | 19 +--- ILSpy/MainWindow.xaml.cs | 110 ++++++++++++++------ ILSpy/Search/SearchPane.cs | 10 +- ILSpy/ViewModels/AnalyzerPaneModel.cs | 7 +- ILSpy/ViewModels/AssemblyListPaneModel.cs | 6 +- ILSpy/ViewModels/DebugStepsPaneModel.cs | 7 +- ILSpy/ViewModels/LegacyToolPaneModel.cs | 32 ++++++ ILSpy/ViewModels/SearchPaneModel.cs | 7 +- ILSpy/ViewModels/ToolPaneModel.cs | 4 + ILSpy/Views/DebugSteps.xaml.cs | 14 +-- 19 files changed, 225 insertions(+), 153 deletions(-) delete mode 100644 ILSpy/IPane.cs create mode 100644 ILSpy/ViewModels/LegacyToolPaneModel.cs diff --git a/ILSpy/Analyzers/AnalyzerTreeView.cs b/ILSpy/Analyzers/AnalyzerTreeView.cs index edbdf43cf..8bc21a665 100644 --- a/ILSpy/Analyzers/AnalyzerTreeView.cs +++ b/ILSpy/Analyzers/AnalyzerTreeView.cs @@ -32,7 +32,7 @@ namespace ICSharpCode.ILSpy.Analyzers /// /// Analyzer tree view. /// - public class AnalyzerTreeView : SharpTreeView, IPane + public class AnalyzerTreeView : SharpTreeView { public AnalyzerTreeView() { @@ -60,7 +60,7 @@ namespace ICSharpCode.ILSpy.Analyzers public void Show() { - AnalyzerPaneModel.Instance.Show(); + DockWorkspace.Instance.ShowToolPane(AnalyzerPaneModel.PaneContentId); } public void Show(AnalyzerTreeNode node) @@ -122,11 +122,6 @@ namespace ICSharpCode.ILSpy.Analyzers throw new ArgumentOutOfRangeException(nameof(entity), $"Entity {entity.GetType().FullName} is not supported."); } } - - void IPane.Closed() - { - this.Root.Children.Clear(); - } sealed class AnalyzerRootNode : AnalyzerTreeNode { diff --git a/ILSpy/Commands/DecompileInNewViewCommand.cs b/ILSpy/Commands/DecompileInNewViewCommand.cs index 35facb748..3069d7c6b 100644 --- a/ILSpy/Commands/DecompileInNewViewCommand.cs +++ b/ILSpy/Commands/DecompileInNewViewCommand.cs @@ -49,7 +49,7 @@ namespace ICSharpCode.ILSpy.Commands IEnumerable GetNodes(TextViewContext context) { if (context.SelectedTreeNodes != null) { - if (context.TreeView != MainWindow.Instance.treeView) { + if (context.TreeView != MainWindow.Instance.AssemblyTreeView) { return context.SelectedTreeNodes.OfType().Select(FindTreeNode).Where(n => n != null); } else { return context.SelectedTreeNodes.OfType().Where(n => n != null); diff --git a/ILSpy/Commands/ExportCommandAttribute.cs b/ILSpy/Commands/ExportCommandAttribute.cs index 2c8f3962f..eaa296682 100644 --- a/ILSpy/Commands/ExportCommandAttribute.cs +++ b/ILSpy/Commands/ExportCommandAttribute.cs @@ -30,7 +30,6 @@ namespace ICSharpCode.ILSpy string ToolbarCategory { get; } object Tag { get; } double ToolbarOrder { get; } - } [MetadataAttribute] @@ -85,4 +84,23 @@ namespace ICSharpCode.ILSpy public double MenuOrder { get; set; } } #endregion + + #region Tool Panes + public interface IToolPaneMetadata + { + string ContentId { get; } + } + + [MetadataAttribute] + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] + public class ExportToolPaneAttribute : ExportAttribute, IToolPaneMetadata + { + public ExportToolPaneAttribute() + : base("ToolPane", typeof(ViewModels.ToolPaneModel)) + { + } + + public string ContentId { get; set; } + } + #endregion } diff --git a/ILSpy/Commands/ShowDebugSteps.cs b/ILSpy/Commands/ShowDebugSteps.cs index a5c3d98fd..bb2ead201 100644 --- a/ILSpy/Commands/ShowDebugSteps.cs +++ b/ILSpy/Commands/ShowDebugSteps.cs @@ -11,7 +11,7 @@ namespace ICSharpCode.ILSpy.Commands { public override void Execute(object parameter) { - DebugStepsPaneModel.Instance.Show(); + DockWorkspace.Instance.ShowToolPane(DebugStepsPaneModel.PaneContentId); } } } diff --git a/ILSpy/Commands/SortAssemblyListCommand.cs b/ILSpy/Commands/SortAssemblyListCommand.cs index 5347f61cc..2222518a6 100644 --- a/ILSpy/Commands/SortAssemblyListCommand.cs +++ b/ILSpy/Commands/SortAssemblyListCommand.cs @@ -29,7 +29,7 @@ namespace ICSharpCode.ILSpy { public override void Execute(object parameter) { - using (MainWindow.Instance.treeView.LockUpdates()) + using (MainWindow.Instance.AssemblyTreeView.LockUpdates()) MainWindow.Instance.CurrentAssemblyList.Sort(this); } @@ -45,8 +45,8 @@ namespace ICSharpCode.ILSpy { public override void Execute(object parameter) { - using (MainWindow.Instance.treeView.LockUpdates()) - CollapseChildren(MainWindow.Instance.treeView.Root); + using (MainWindow.Instance.AssemblyTreeView.LockUpdates()) + CollapseChildren(MainWindow.Instance.AssemblyTreeView.Root); void CollapseChildren(SharpTreeNode node) { diff --git a/ILSpy/Docking/DockWorkspace.cs b/ILSpy/Docking/DockWorkspace.cs index 8bc68e07b..f94ad7eff 100644 --- a/ILSpy/Docking/DockWorkspace.cs +++ b/ILSpy/Docking/DockWorkspace.cs @@ -22,6 +22,7 @@ using System.Collections.ObjectModel; using System.ComponentModel; using System.ComponentModel.Composition; using System.Linq; +using System.Reflection; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; @@ -34,7 +35,7 @@ using Xceed.Wpf.AvalonDock.Layout.Serialization; namespace ICSharpCode.ILSpy.Docking { - public class DockWorkspace : INotifyPropertyChanged + public class DockWorkspace : INotifyPropertyChanged, ILayoutUpdateStrategy { private SessionSettings sessionSettings; @@ -58,21 +59,16 @@ namespace ICSharpCode.ILSpy.Docking public PaneCollection TabPages { get; } = new PaneCollection(); - private ToolPaneModel[] toolPanes; - public IEnumerable ToolPanes { - get { - if (toolPanes == null) { - toolPanes = new ToolPaneModel[] { - AssemblyListPaneModel.Instance, - SearchPaneModel.Instance, - AnalyzerPaneModel.Instance, -#if DEBUG - DebugStepsPaneModel.Instance, -#endif - }; - } - return toolPanes; + public ObservableCollection ToolPanes { get; } = new ObservableCollection(); + + public bool ShowToolPane(string contentId) + { + var pane = ToolPanes.FirstOrDefault(p => p.ContentId == contentId); + if (pane != null) { + pane.Show(); + return true; } + return false; } public void Remove(PaneModel model) @@ -103,6 +99,7 @@ namespace ICSharpCode.ILSpy.Docking public void InitializeLayout(Xceed.Wpf.AvalonDock.DockingManager manager) { + manager.LayoutUpdateStrategy = this; XmlLayoutSerializer serializer = new XmlLayoutSerializer(manager); serializer.LayoutSerializationCallback += LayoutSerializationCallback; try { @@ -116,25 +113,8 @@ namespace ICSharpCode.ILSpy.Docking { switch (e.Model) { case LayoutAnchorable la: - switch (la.ContentId) { - case AssemblyListPaneModel.PaneContentId: - e.Content = AssemblyListPaneModel.Instance; - break; - case SearchPaneModel.PaneContentId: - e.Content = SearchPaneModel.Instance; - break; - case AnalyzerPaneModel.PaneContentId: - e.Content = AnalyzerPaneModel.Instance; - break; -#if DEBUG - case DebugStepsPaneModel.PaneContentId: - e.Content = DebugStepsPaneModel.Instance; - break; -#endif - default: - e.Cancel = true; - break; - } + e.Content = ToolPanes.FirstOrDefault(p => p.ContentId == la.ContentId); + e.Cancel = e.Content == null; la.CanDockAsTabbedDocument = false; if (!e.Cancel) { e.Cancel = ((ToolPaneModel)e.Content).IsVisible; @@ -203,5 +183,50 @@ namespace ICSharpCode.ILSpy.Docking InitializeLayout(MainWindow.Instance.DockManager); MainWindow.Instance.Dispatcher.BeginInvoke(DispatcherPriority.Background, (Action)MainWindow.Instance.RefreshDecompiledView); } + + static readonly PropertyInfo previousContainerProperty = typeof(LayoutContent).GetProperty("PreviousContainer", BindingFlags.NonPublic | BindingFlags.Instance); + + public bool BeforeInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableToShow, ILayoutContainer destinationContainer) + { + if (!(anchorableToShow.Content is LegacyToolPaneModel legacyContent)) + return false; + anchorableToShow.CanDockAsTabbedDocument = false; + + LayoutAnchorablePane previousContainer; + switch (legacyContent.Location) { + case LegacyToolPaneLocation.Top: + previousContainer = GetContainer(); + previousContainer.Children.Add(anchorableToShow); + return true; + case LegacyToolPaneLocation.Bottom: + previousContainer = GetContainer(); + previousContainer.Children.Add(anchorableToShow); + return true; + default: + return false; + } + + LayoutAnchorablePane GetContainer() + { + var anchorable = layout.Descendents().OfType().FirstOrDefault(x => x.Content is T) + ?? layout.Hidden.First(x => x.Content is T); + return (LayoutAnchorablePane)previousContainerProperty.GetValue(anchorable) ?? (LayoutAnchorablePane)anchorable.Parent; + } + } + + public void AfterInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableShown) + { + anchorableShown.IsActive = true; + anchorableShown.IsSelected = true; + } + + public bool BeforeInsertDocument(LayoutRoot layout, LayoutDocument anchorableToShow, ILayoutContainer destinationContainer) + { + return false; + } + + public void AfterInsertDocument(LayoutRoot layout, LayoutDocument anchorableShown) + { + } } } diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index fc1bfc95b..633c777ff 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -208,6 +208,7 @@ + @@ -248,7 +249,6 @@ - diff --git a/ILSpy/IPane.cs b/ILSpy/IPane.cs deleted file mode 100644 index d429b6cb2..000000000 --- a/ILSpy/IPane.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// 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. - - -namespace ICSharpCode.ILSpy -{ - public interface IPane - { - void Closed(); - } -} diff --git a/ILSpy/Languages/ILAstLanguage.cs b/ILSpy/Languages/ILAstLanguage.cs index d7c100990..5aca29d64 100644 --- a/ILSpy/Languages/ILAstLanguage.cs +++ b/ILSpy/Languages/ILAstLanguage.cs @@ -141,7 +141,7 @@ namespace ICSharpCode.ILSpy } } (output as ISmartTextOutput)?.AddButton(Images.ViewCode, "Show Steps", delegate { - DebugStepsPaneModel.Instance.Show(); + Docking.DockWorkspace.Instance.ShowToolPane(DebugStepsPaneModel.PaneContentId); }); output.WriteLine(); il.WriteTo(output, DebugSteps.Options); diff --git a/ILSpy/MainWindow.xaml b/ILSpy/MainWindow.xaml index 3eb590066..479293aa4 100644 --- a/ILSpy/MainWindow.xaml +++ b/ILSpy/MainWindow.xaml @@ -16,7 +16,6 @@ MinHeight="200" UseLayoutRounding="True" TextOptions.TextFormattingMode="Display" - FocusManager.FocusedElement="{Binding ElementName=treeView}" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" d:DesignHeight="500" d:DesignWidth="500" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" > @@ -24,7 +23,7 @@ - - + @@ -169,7 +168,7 @@ @@ -185,18 +184,6 @@ - - - - - - - - - - - - diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index ec23b1740..5ef3f010f 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -84,9 +84,9 @@ namespace ICSharpCode.ILSpy internal AssemblyListManager AssemblyListManager { get; } - public SharpTreeView treeView { + public SharpTreeView AssemblyTreeView { get { - return FindResource("TreeView") as SharpTreeView; + return FindResource("AssemblyTreeView") as SharpTreeView; } } @@ -120,13 +120,13 @@ namespace ICSharpCode.ILSpy DockWorkspace.Instance.LoadSettings(sessionSettings); InitializeComponent(); + InitToolPanes(); DockWorkspace.Instance.InitializeLayout(DockManager); sessionSettings.FilterSettings.PropertyChanged += filterSettings_PropertyChanged; sessionSettings.PropertyChanged += SessionSettings_PropertyChanged; - InitMainMenu(); InitToolbar(); - ContextMenuProvider.Add(treeView); + ContextMenuProvider.Add(AssemblyTreeView); this.Loaded += MainWindow_Loaded; } @@ -231,6 +231,48 @@ namespace ICSharpCode.ILSpy } #endregion + #region Tool Pane extensibility + private void InitToolPanes() + { + var toolPanes = App.ExportProvider.GetExports("ToolPane"); + var templateSelector = new PaneTemplateSelector(); + templateSelector.Mappings.Add(new TemplateMapping { + Type = typeof(TabPageModel), + Template = (DataTemplate)FindResource("DefaultContentTemplate") + }); + templateSelector.Mappings.Add(new TemplateMapping { + Type = typeof(LegacyToolPaneModel), + Template = (DataTemplate)FindResource("DefaultContentTemplate") + }); + foreach (var toolPane in toolPanes) { + ToolPaneModel model = toolPane.Value; + templateSelector.Mappings.Add(new TemplateMapping { Type = model.GetType(), Template = model.Template }); + DockWorkspace.Instance.ToolPanes.Add(model); + } + DockManager.LayoutItemTemplateSelector = templateSelector; + } + + public void ShowInTopPane(string title, object content) + { + var model = DockWorkspace.Instance.ToolPanes.OfType().FirstOrDefault(p => p.Content == content); + if (model == null) { + model = new LegacyToolPaneModel(title, content, LegacyToolPaneLocation.Top); + DockWorkspace.Instance.ToolPanes.Add(model); + } + model.Show(); + } + + public void ShowInBottomPane(string title, object content) + { + var model = DockWorkspace.Instance.ToolPanes.OfType().FirstOrDefault(p => p.Content == content); + if (model == null) { + model = new LegacyToolPaneModel(title, content, LegacyToolPaneLocation.Bottom); + DockWorkspace.Instance.ToolPanes.Add(model); + } + model.Show(); + } + #endregion + #region Message Hook protected override void OnSourceInitialized(EventArgs e) { @@ -337,7 +379,7 @@ namespace ICSharpCode.ILSpy async void NavigateOnLaunch(string navigateTo, string[] activeTreeViewPath, ILSpySettings spySettings, List relevantAssemblies) { - var initialSelection = treeView.SelectedItem; + var initialSelection = AssemblyTreeView.SelectedItem; if (navigateTo != null) { bool found = false; if (navigateTo.StartsWith("N:", StringComparison.Ordinal)) { @@ -351,7 +393,7 @@ namespace ICSharpCode.ILSpy NamespaceTreeNode nsNode = asmNode.FindNamespaceNode(namespaceName); if (nsNode != null) { found = true; - if (treeView.SelectedItem == initialSelection) { + if (AssemblyTreeView.SelectedItem == initialSelection) { SelectNode(nsNode); } break; @@ -366,12 +408,12 @@ namespace ICSharpCode.ILSpy IEntity mr = await Task.Run(() => FindEntityInRelevantAssemblies(navigateTo, relevantAssemblies)); if (mr != null && mr.ParentModule.PEFile != null) { found = true; - if (treeView.SelectedItem == initialSelection) { + if (AssemblyTreeView.SelectedItem == initialSelection) { JumpToReference(mr); } } } - if (!found && treeView.SelectedItem == initialSelection) { + if (!found && AssemblyTreeView.SelectedItem == initialSelection) { AvalonEditTextOutput output = new AvalonEditTextOutput(); output.Write(string.Format("Cannot find '{0}' in command line specified assemblies.", navigateTo)); DockWorkspace.Instance.ShowText(output); @@ -380,7 +422,7 @@ namespace ICSharpCode.ILSpy // NavigateTo == null and an assembly was given on the command-line: // Select the newly loaded assembly AssemblyTreeNode asmNode = assemblyListTreeNode.FindAssemblyNode(relevantAssemblies[0]); - if (asmNode != null && treeView.SelectedItem == initialSelection) { + if (asmNode != null && AssemblyTreeView.SelectedItem == initialSelection) { SelectNode(asmNode); } } else if (spySettings != null) { @@ -395,7 +437,7 @@ namespace ICSharpCode.ILSpy } node = FindNodeByPath(activeTreeViewPath, true); } - if (treeView.SelectedItem == initialSelection) { + if (AssemblyTreeView.SelectedItem == initialSelection) { if (node != null) { SelectNode(node); @@ -611,7 +653,7 @@ namespace ICSharpCode.ILSpy assemblyListTreeNode = new AssemblyListTreeNode(assemblyList); assemblyListTreeNode.FilterSettings = sessionSettings.FilterSettings.Clone(); assemblyListTreeNode.Select = x => SelectNode(x, inNewTabPage: false); - treeView.Root = assemblyListTreeNode; + AssemblyTreeView.Root = assemblyListTreeNode; if (assemblyList.ListName == AssemblyListManager.DefaultListName) #if DEBUG @@ -695,12 +737,12 @@ namespace ICSharpCode.ILSpy LanguageVersion = CurrentLanguageVersion }); DockWorkspace.Instance.ActiveTabPage = DockWorkspace.Instance.TabPages.Last(); - treeView.SelectedItem = null; + AssemblyTreeView.SelectedItem = null; } // Set both the selection and focus to ensure that keyboard navigation works as expected. - treeView.FocusNode(obj); - treeView.SelectedItem = obj; + AssemblyTreeView.FocusNode(obj); + AssemblyTreeView.SelectedItem = obj; } else { MessageBox.Show("Navigation failed because the target is hidden or a compiler-generated class.\n" + "Please disable all filters that might hide the item (i.e. activate " + @@ -722,8 +764,8 @@ namespace ICSharpCode.ILSpy DockWorkspace.Instance.ActiveTabPage = DockWorkspace.Instance.TabPages.Last(); } - treeView.FocusNode(nodes.First()); - treeView.SetSelectedNodes(nodes); + AssemblyTreeView.FocusNode(nodes.First()); + AssemblyTreeView.SetSelectedNodes(nodes); } } @@ -734,7 +776,7 @@ namespace ICSharpCode.ILSpy { if (path == null) return null; - SharpTreeNode node = treeView.Root; + SharpTreeNode node = AssemblyTreeView.Root; SharpTreeNode bestMatch = node; foreach (var element in path) { if (node == null) @@ -887,7 +929,7 @@ namespace ICSharpCode.ILSpy throw new ArgumentNullException(nameof(fileNames)); if (focusNode) - treeView.UnselectAll(); + AssemblyTreeView.UnselectAll(); LoadAssemblies(fileNames, focusNode: focusNode); } @@ -913,7 +955,7 @@ namespace ICSharpCode.ILSpy else { var node = assemblyListTreeNode.FindAssemblyNode(nugetAsm); if (node != null && focusNode) { - treeView.SelectedItems.Add(node); + AssemblyTreeView.SelectedItems.Add(node); lastNode = node; } } @@ -931,7 +973,7 @@ namespace ICSharpCode.ILSpy else { var node = assemblyListTreeNode.FindAssemblyNode(asm); if (node != null && focusNode) { - treeView.SelectedItems.Add(node); + AssemblyTreeView.SelectedItems.Add(node); lastNode = node; } } @@ -940,7 +982,7 @@ namespace ICSharpCode.ILSpy } if (lastNode != null && focusNode) - treeView.FocusNode(lastNode); + AssemblyTreeView.FocusNode(lastNode); } } @@ -953,7 +995,7 @@ namespace ICSharpCode.ILSpy { try { refreshInProgress = true; - var path = GetPathForNode(treeView.SelectedItem as SharpTreeNode); + var path = GetPathForNode(AssemblyTreeView.SelectedItem as SharpTreeNode); ShowAssemblyList(AssemblyListManager.LoadList(ILSpySettings.Load(), assemblyList.ListName)); SelectNode(FindNodeByPath(path, true)); } finally { @@ -963,7 +1005,7 @@ namespace ICSharpCode.ILSpy void SearchCommandExecuted(object sender, ExecutedRoutedEventArgs e) { - SearchPaneModel.Instance.Show(); + DockWorkspace.Instance.ShowToolPane(SearchPaneModel.PaneContentId); } #endregion @@ -983,20 +1025,20 @@ namespace ICSharpCode.ILSpy if (ignoreDecompilationRequests) return; - if (treeView.SelectedItems.Count == 0 && refreshInProgress) + if (AssemblyTreeView.SelectedItems.Count == 0 && refreshInProgress) return; if (recordHistory) { var currentState = DockWorkspace.Instance.ActiveTabPage.GetState(); if (currentState != null) history.UpdateCurrent(new NavigationState(currentState)); - history.Record(new NavigationState(treeView.SelectedItems.OfType())); + history.Record(new NavigationState(AssemblyTreeView.SelectedItems.OfType())); } DockWorkspace.Instance.ActiveTabPage.SupportsLanguageSwitching = true; - if (treeView.SelectedItems.Count == 1) { - ILSpyTreeNode node = treeView.SelectedItem as ILSpyTreeNode; + if (AssemblyTreeView.SelectedItems.Count == 1) { + ILSpyTreeNode node = AssemblyTreeView.SelectedItem as ILSpyTreeNode; if (node != null && node.View(DockWorkspace.Instance.ActiveTabPage)) return; } @@ -1035,7 +1077,7 @@ namespace ICSharpCode.ILSpy public IEnumerable SelectedNodes { get { - return treeView.GetTopLevelSelection().OfType(); + return AssemblyTreeView.GetTopLevelSelection().OfType(); } } #endregion @@ -1077,12 +1119,12 @@ namespace ICSharpCode.ILSpy var newState = forward ? history.GoForward() : history.GoBack(); ignoreDecompilationRequests = true; - treeView.SelectedItems.Clear(); + AssemblyTreeView.SelectedItems.Clear(); foreach (var node in newState.TreeNodes) { - treeView.SelectedItems.Add(node); + AssemblyTreeView.SelectedItems.Add(node); } if (newState.TreeNodes.Any()) - treeView.FocusNode(newState.TreeNodes.First()); + AssemblyTreeView.FocusNode(newState.TreeNodes.First()); ignoreDecompilationRequests = false; DecompileSelectedNodes(newState.ViewState as DecompilerTextViewState, false); } @@ -1142,8 +1184,8 @@ namespace ICSharpCode.ILSpy { base.OnClosing(e); sessionSettings.ActiveAssemblyList = assemblyList.ListName; - sessionSettings.ActiveTreeViewPath = GetPathForNode(treeView.SelectedItem as SharpTreeNode); - sessionSettings.ActiveAutoLoadedAssembly = GetAutoLoadedAssemblyNode(treeView.SelectedItem as SharpTreeNode); + sessionSettings.ActiveTreeViewPath = GetPathForNode(AssemblyTreeView.SelectedItem as SharpTreeNode); + sessionSettings.ActiveAutoLoadedAssembly = GetAutoLoadedAssemblyNode(AssemblyTreeView.SelectedItem as SharpTreeNode); sessionSettings.WindowBounds = this.RestoreBounds; sessionSettings.DockLayout.Serialize(new XmlLayoutSerializer(DockManager)); sessionSettings.Save(); @@ -1167,7 +1209,7 @@ namespace ICSharpCode.ILSpy public void UnselectAll() { - treeView.UnselectAll(); + AssemblyTreeView.UnselectAll(); } public void SetStatus(string status, Brush foreground) diff --git a/ILSpy/Search/SearchPane.cs b/ILSpy/Search/SearchPane.cs index 6fc3862c5..c74173c1c 100644 --- a/ILSpy/Search/SearchPane.cs +++ b/ILSpy/Search/SearchPane.cs @@ -23,6 +23,7 @@ using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; +using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows; @@ -40,7 +41,7 @@ namespace ICSharpCode.ILSpy /// /// Search pane /// - public partial class SearchPane : UserControl, IPane + public partial class SearchPane : UserControl { const int MAX_RESULTS = 1000; const int MAX_REFRESH_TIME_MS = 10; // More means quicker forward of data, less means better responsibility @@ -105,7 +106,7 @@ namespace ICSharpCode.ILSpy public void Show() { if (!IsVisible) { - SearchPaneModel.Instance.IsVisible = true; + DockWorkspace.Instance.ToolPanes.Single(p => p.ContentId == SearchPaneModel.PaneContentId).IsVisible = true; if (runSearchOnNextShow) { runSearchOnNextShow = false; StartSearch(this.SearchTerm); @@ -139,11 +140,6 @@ namespace ICSharpCode.ILSpy MainWindow.Instance.SessionSettings.SelectedSearchMode = (SearchMode)searchModeComboBox.SelectedIndex; StartSearch(this.SearchTerm); } - - void IPane.Closed() - { - this.SearchTerm = string.Empty; - } void ListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e) { diff --git a/ILSpy/ViewModels/AnalyzerPaneModel.cs b/ILSpy/ViewModels/AnalyzerPaneModel.cs index 57c4513fd..28b07734c 100644 --- a/ILSpy/ViewModels/AnalyzerPaneModel.cs +++ b/ILSpy/ViewModels/AnalyzerPaneModel.cs @@ -16,18 +16,21 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using System.Windows; + namespace ICSharpCode.ILSpy.ViewModels { + [ExportToolPane(ContentId = PaneContentId)] public class AnalyzerPaneModel : ToolPaneModel { public const string PaneContentId = "analyzerPane"; - public static AnalyzerPaneModel Instance { get; } = new AnalyzerPaneModel(); - private AnalyzerPaneModel() { ContentId = PaneContentId; Title = Properties.Resources.Analyze; } + + public override DataTemplate Template => (DataTemplate)MainWindow.Instance.FindResource("AnalyzerPaneTemplate"); } } diff --git a/ILSpy/ViewModels/AssemblyListPaneModel.cs b/ILSpy/ViewModels/AssemblyListPaneModel.cs index 009958d41..386cc1c1d 100644 --- a/ILSpy/ViewModels/AssemblyListPaneModel.cs +++ b/ILSpy/ViewModels/AssemblyListPaneModel.cs @@ -16,21 +16,23 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using System.Windows; using ICSharpCode.ILSpy.Properties; namespace ICSharpCode.ILSpy.ViewModels { + [ExportToolPane(ContentId = PaneContentId)] public class AssemblyListPaneModel : ToolPaneModel { public const string PaneContentId = "assemblyListPane"; - public static AssemblyListPaneModel Instance { get; } = new AssemblyListPaneModel(); - private AssemblyListPaneModel() { Title = Resources.Assemblies; ContentId = PaneContentId; IsCloseable = false; } + + public override DataTemplate Template => (DataTemplate)MainWindow.Instance.FindResource("AssemblyListPaneTemplate"); } } diff --git a/ILSpy/ViewModels/DebugStepsPaneModel.cs b/ILSpy/ViewModels/DebugStepsPaneModel.cs index f7e9f2faf..7ea45bb6a 100644 --- a/ILSpy/ViewModels/DebugStepsPaneModel.cs +++ b/ILSpy/ViewModels/DebugStepsPaneModel.cs @@ -16,18 +16,21 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using System.Windows; + namespace ICSharpCode.ILSpy.ViewModels { + [ExportToolPane(ContentId = PaneContentId)] public class DebugStepsPaneModel : ToolPaneModel { public const string PaneContentId = "debugStepsPane"; - public static DebugStepsPaneModel Instance { get; } = new DebugStepsPaneModel(); - private DebugStepsPaneModel() { ContentId = PaneContentId; Title = Properties.Resources.DebugSteps; } + + public override DataTemplate Template => (DataTemplate)MainWindow.Instance.FindResource("DebugStepsPaneTemplate"); } } diff --git a/ILSpy/ViewModels/LegacyToolPaneModel.cs b/ILSpy/ViewModels/LegacyToolPaneModel.cs new file mode 100644 index 000000000..40ecc4cb2 --- /dev/null +++ b/ILSpy/ViewModels/LegacyToolPaneModel.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace ICSharpCode.ILSpy.ViewModels +{ + internal enum LegacyToolPaneLocation + { + Top, + Bottom + } + + internal class LegacyToolPaneModel : ToolPaneModel + { + public LegacyToolPaneModel(string title, object content, LegacyToolPaneLocation location) + { + this.Title = title; + this.Content = content; + this.IsCloseable = true; + this.Location = location; + } + + public object Content { get; } + + public override DataTemplate Template => throw new NotSupportedException(); + + public LegacyToolPaneLocation Location { get; } + } +} diff --git a/ILSpy/ViewModels/SearchPaneModel.cs b/ILSpy/ViewModels/SearchPaneModel.cs index ac1208281..66a156825 100644 --- a/ILSpy/ViewModels/SearchPaneModel.cs +++ b/ILSpy/ViewModels/SearchPaneModel.cs @@ -16,14 +16,15 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using System.Windows; + namespace ICSharpCode.ILSpy.ViewModels { + [ExportToolPane(ContentId = PaneContentId)] public class SearchPaneModel : ToolPaneModel { public const string PaneContentId = "searchPane"; - public static SearchPaneModel Instance { get; } = new SearchPaneModel(); - private SearchPaneModel() { ContentId = PaneContentId; @@ -36,5 +37,7 @@ namespace ICSharpCode.ILSpy.ViewModels base.Show(); MainWindow.Instance.SearchPane.Show(); } + + public override DataTemplate Template => (DataTemplate)MainWindow.Instance.FindResource("SearchPaneTemplate"); } } diff --git a/ILSpy/ViewModels/ToolPaneModel.cs b/ILSpy/ViewModels/ToolPaneModel.cs index f28574d25..672273674 100644 --- a/ILSpy/ViewModels/ToolPaneModel.cs +++ b/ILSpy/ViewModels/ToolPaneModel.cs @@ -16,6 +16,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using System.Windows; + namespace ICSharpCode.ILSpy.ViewModels { public abstract class ToolPaneModel : PaneModel @@ -25,5 +27,7 @@ namespace ICSharpCode.ILSpy.ViewModels this.IsActive = true; this.IsVisible = true; } + + public abstract DataTemplate Template { get; } } } diff --git a/ILSpy/Views/DebugSteps.xaml.cs b/ILSpy/Views/DebugSteps.xaml.cs index 1c7d9e5fb..d0870f496 100644 --- a/ILSpy/Views/DebugSteps.xaml.cs +++ b/ILSpy/Views/DebugSteps.xaml.cs @@ -9,7 +9,7 @@ using ICSharpCode.ILSpy.ViewModels; namespace ICSharpCode.ILSpy { - public partial class DebugSteps : UserControl, IPane + public partial class DebugSteps : UserControl { static readonly ILAstWritingOptions writingOptions = new ILAstWritingOptions { UseFieldSugar = true, @@ -79,18 +79,6 @@ namespace ICSharpCode.ILSpy #endif } - void IPane.Closed() - { -#if DEBUG - MainWindow.Instance.SessionSettings.FilterSettings.PropertyChanged -= FilterSettings_PropertyChanged; - MainWindow.Instance.SelectionChanged -= SelectionChanged; - writingOptions.PropertyChanged -= WritingOptions_PropertyChanged; - if (language != null) { - language.StepperUpdated -= ILAstStepperUpdated; - } -#endif - } - private void ShowStateAfter_Click(object sender, RoutedEventArgs e) { Stepper.Node n = (Stepper.Node)tree.SelectedItem;