diff --git a/ICSharpCode.ILSpyX/TreeView/SharpTreeNode.cs b/ICSharpCode.ILSpyX/TreeView/SharpTreeNode.cs
index a63fc98174..ea54bd4e18 100644
--- a/ICSharpCode.ILSpyX/TreeView/SharpTreeNode.cs
+++ b/ICSharpCode.ILSpyX/TreeView/SharpTreeNode.cs
@@ -323,9 +323,26 @@ public bool LazyLoading {
}
RaisePropertyChanged(nameof(LazyLoading));
RaisePropertyChanged(nameof(ShowExpander));
+ RaisePropertyChanged(nameof(ViewChildren));
}
}
+ ///
+ /// Workaround for cross platform treeview bindings.
+ ///
+ public System.Collections.IEnumerable ViewChildren {
+ get {
+ if (LazyLoading && Children.Count == 0)
+ return new[] { new LoadingTreeNode() };
+ return Children;
+ }
+ }
+
+ class LoadingTreeNode : SharpTreeNode
+ {
+ public override object Text => "Loading...";
+ }
+
bool canExpandRecursively = true;
///
diff --git a/ICSharpCode.ILSpyX/TreeView/SharpTreeNodeCollection.cs b/ICSharpCode.ILSpyX/TreeView/SharpTreeNodeCollection.cs
index a778531554..63b03e7780 100644
--- a/ICSharpCode.ILSpyX/TreeView/SharpTreeNodeCollection.cs
+++ b/ICSharpCode.ILSpyX/TreeView/SharpTreeNodeCollection.cs
@@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
@@ -29,7 +30,7 @@ namespace ICSharpCode.ILSpyX.TreeView
///
/// Collection that validates that inserted nodes do not have another parent.
///
- public sealed class SharpTreeNodeCollection : IList, INotifyCollectionChanged
+ public sealed class SharpTreeNodeCollection : IList, IList, INotifyCollectionChanged
{
readonly SharpTreeNode parent;
List list = new List();
@@ -94,6 +95,20 @@ bool ICollection.IsReadOnly {
get { return false; }
}
+ #region IList Members
+
+ public bool IsFixedSize => ((IList)list).IsFixedSize;
+
+ public bool IsReadOnly => ((IList)list).IsReadOnly;
+
+ public bool IsSynchronized => ((ICollection)list).IsSynchronized;
+
+ public object SyncRoot => ((ICollection)list).SyncRoot;
+
+ object IList.this[int index] { get => this[index]; set => this[index] = (SharpTreeNode)value; }
+
+ #endregion
+
public int IndexOf(SharpTreeNode node)
{
if (node == null || node.modelParent != parent)
@@ -236,5 +251,52 @@ public void RemoveAll(Predicate match)
RemoveRange(firstToRemove, list.Count - firstToRemove);
}
}
+
+ public int Add(object value)
+ {
+ if (value == null)
+ throw new ArgumentNullException(nameof(value));
+ if (!(value is SharpTreeNode node))
+ throw new ArgumentException("Value must be a SharpTreeNode", nameof(value));
+ Add(node);
+ return list.IndexOf(node);
+ }
+
+ public bool Contains(object value)
+ {
+ return value is SharpTreeNode node && Contains(node);
+ }
+
+ public int IndexOf(object value)
+ {
+ return value is SharpTreeNode node ? IndexOf(node) : -1;
+ }
+
+ public void Insert(int index, object value)
+ {
+ if (value == null)
+ throw new ArgumentNullException(nameof(value));
+ if (!(value is SharpTreeNode node))
+ throw new ArgumentException("Value must be a SharpTreeNode", nameof(value));
+ Insert(index, node);
+ }
+
+ public void Remove(object value)
+ {
+ if (value is SharpTreeNode node)
+ Remove(node);
+ }
+
+ public void CopyTo(Array array, int index)
+ {
+ if (array is SharpTreeNode[] nodes)
+ {
+ CopyTo(nodes, index);
+ }
+ else
+ {
+ ((ICollection)list).CopyTo(array, index);
+ }
+ }
}
}
diff --git a/ILSpy/AboutPage.cs b/ILSpy/AboutPage.cs
index f53e1e7470..09b9c84967 100644
--- a/ILSpy/AboutPage.cs
+++ b/ILSpy/AboutPage.cs
@@ -192,7 +192,11 @@ static void ShowAvailableVersion(AvailableVersionInfo availableVersion, StackPan
stackPanel.Children.Add(
new Image {
Width = 16, Height = 16,
+#if CROSS_PLATFORM
+ Source = Images.LoadImage(Images.OK),
+#else
Source = Images.OK,
+#endif
Margin = new Thickness(4, 0, 4, 0)
});
stackPanel.Children.Add(
diff --git a/ILSpy/AssemblyTree/AssemblyTreeModel.cs b/ILSpy/AssemblyTree/AssemblyTreeModel.cs
index fecdac55e7..0d22f9b281 100644
--- a/ILSpy/AssemblyTree/AssemblyTreeModel.cs
+++ b/ILSpy/AssemblyTree/AssemblyTreeModel.cs
@@ -29,7 +29,6 @@
using System.Reflection.Metadata.Ecma335;
using System.Threading.Tasks;
using System.Windows;
-using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Navigation;
using System.Windows.Threading;
@@ -57,7 +56,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
{
[ExportToolPane]
[Shared]
- public class AssemblyTreeModel : ToolPaneModel
+ public partial class AssemblyTreeModel : ToolPaneModel
{
public const string PaneContentId = "assemblyListPane";
@@ -74,36 +73,6 @@ public class AssemblyTreeModel : ToolPaneModel
private static Dispatcher UIThreadDispatcher => Application.Current.Dispatcher;
- public AssemblyTreeModel(SettingsService settingsService, LanguageService languageService, IExportProvider exportProvider)
- {
- this.settingsService = settingsService;
- this.languageService = languageService;
- this.exportProvider = exportProvider;
-
- Title = Resources.Assemblies;
- ContentId = PaneContentId;
- IsCloseable = false;
- ShortcutKey = new KeyGesture(Key.F6);
-
- MessageBus.Subscribers += JumpToReference;
- MessageBus.Subscribers += (sender, e) => Settings_PropertyChanged(sender, e);
- MessageBus.Subscribers += ApplySessionSettings;
- MessageBus.Subscribers += ActiveTabPageChanged;
- MessageBus.Subscribers += (_, e) => history.RemoveAll(s => !DockWorkspace.TabPages.Contains(s.TabPage));
- MessageBus.Subscribers += ResetLayout;
- MessageBus.Subscribers += (_, e) => NavigateTo(e.Request, e.InNewTabPage);
- MessageBus.Subscribers += (_, _) => {
- Initialize();
- Show();
- };
-
- EventManager.RegisterClassHandler(typeof(Window), Hyperlink.RequestNavigateEvent, new RequestNavigateEventHandler((_, e) => NavigateTo(e)));
-
- refreshThrottle = new(DispatcherPriority.Background, RefreshInternal);
-
- AssemblyList = settingsService.CreateEmptyAssemblyList();
- }
-
private void Settings_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (sender is SessionSettings sessionSettings)
@@ -161,6 +130,9 @@ public SharpTreeNode[] SelectedItems {
var oldSelection = selectedItems;
selectedItems = value;
OnPropertyChanged();
+#if CROSS_PLATFORM
+ OnPropertyChanged(nameof(SelectedItem));
+#endif
TreeView_SelectionChanged(oldSelection, selectedItems);
}
}
@@ -494,24 +466,6 @@ private void assemblyList_CollectionChanged(object? sender, NotifyCollectionChan
MessageBus.Send(this, new CurrentAssemblyListChangedEventArgs(e));
}
- private static void LoadInitialAssemblies(AssemblyList assemblyList)
- {
- // Called when loading an empty assembly list; so that
- // the user can see something initially.
- System.Reflection.Assembly[] initialAssemblies = {
- typeof(object).Assembly,
- typeof(Uri).Assembly,
- typeof(System.Linq.Enumerable).Assembly,
- typeof(System.Xml.XmlDocument).Assembly,
- typeof(System.Windows.Markup.MarkupExtension).Assembly,
- typeof(System.Windows.Rect).Assembly,
- typeof(System.Windows.UIElement).Assembly,
- typeof(System.Windows.FrameworkElement).Assembly
- };
- foreach (System.Reflection.Assembly asm in initialAssemblies)
- assemblyList.OpenAssembly(asm.Location);
- }
-
public AssemblyTreeNode? FindAssemblyNode(LoadedAssembly asm)
{
return assemblyListTreeNode?.FindAssemblyNode(asm);
@@ -542,10 +496,16 @@ public void SelectNode(SharpTreeNode? node, bool inNewTabPage = false)
}
else
{
+#if CROSS_PLATFORM
+ ExpandAncestors(node);
+#endif
activeView?.ScrollIntoView(node);
SelectedItem = node;
UIThreadDispatcher.BeginInvoke(DispatcherPriority.Background, () => {
+#if CROSS_PLATFORM
+ SelectedItem = node;
+#endif
activeView?.ScrollIntoView(node);
});
}
@@ -1011,6 +971,15 @@ private IEnumerable GetTopLevelSelection()
return selection.Where(item => item.Ancestors().All(a => !selectionHash.Contains(a)));
}
+ void ExpandAncestors(SharpTreeNode node)
+ {
+ foreach (var ancestor in node.Ancestors().Reverse())
+ {
+ ancestor.EnsureLazyChildren();
+ ancestor.IsExpanded = true;
+ }
+ }
+
public void SetActiveView(AssemblyListPane activeView)
{
this.activeView = activeView;
diff --git a/ILSpy/AssemblyTree/AssemblyTreeModel.wpf.cs b/ILSpy/AssemblyTree/AssemblyTreeModel.wpf.cs
new file mode 100644
index 0000000000..9c3f49cb1d
--- /dev/null
+++ b/ILSpy/AssemblyTree/AssemblyTreeModel.wpf.cs
@@ -0,0 +1,83 @@
+// Copyright (c) 2019 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.
+
+using System;
+using System.Windows;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Navigation;
+using System.Windows.Threading;
+
+using ICSharpCode.ILSpy.Properties;
+using ICSharpCode.ILSpyX;
+
+using TomsToolbox.Composition;
+
+namespace ICSharpCode.ILSpy.AssemblyTree
+{
+ public partial class AssemblyTreeModel
+ {
+ public AssemblyTreeModel(SettingsService settingsService, LanguageService languageService, IExportProvider exportProvider)
+ {
+ this.settingsService = settingsService;
+ this.languageService = languageService;
+ this.exportProvider = exportProvider;
+
+ Title = Resources.Assemblies;
+ ContentId = PaneContentId;
+ IsCloseable = false;
+ ShortcutKey = new KeyGesture(Key.F6);
+
+ MessageBus.Subscribers += JumpToReference;
+ MessageBus.Subscribers += (sender, e) => Settings_PropertyChanged(sender, e);
+ MessageBus.Subscribers += ApplySessionSettings;
+ MessageBus.Subscribers += ActiveTabPageChanged;
+ MessageBus.Subscribers += (_, e) => history.RemoveAll(s => !DockWorkspace.TabPages.Contains(s.TabPage));
+ MessageBus.Subscribers += ResetLayout;
+ MessageBus.Subscribers += (_, e) => NavigateTo(e.Request, e.InNewTabPage);
+ MessageBus.Subscribers += (_, _) => {
+ Initialize();
+ Show();
+ };
+
+ EventManager.RegisterClassHandler(typeof(Window), Hyperlink.RequestNavigateEvent, new RequestNavigateEventHandler((_, e) => NavigateTo(e)));
+
+ refreshThrottle = new(DispatcherPriority.Background, RefreshInternal);
+
+ AssemblyList = settingsService.CreateEmptyAssemblyList();
+ }
+
+ private static void LoadInitialAssemblies(AssemblyList assemblyList)
+ {
+ // Called when loading an empty assembly list; so that
+ // the user can see something initially.
+ System.Reflection.Assembly[] initialAssemblies = {
+ typeof(object).Assembly,
+ typeof(Uri).Assembly,
+ typeof(System.Linq.Enumerable).Assembly,
+ typeof(System.Xml.XmlDocument).Assembly,
+ typeof(System.Windows.Markup.MarkupExtension).Assembly,
+ typeof(System.Windows.Rect).Assembly,
+ typeof(System.Windows.UIElement).Assembly,
+ typeof(System.Windows.FrameworkElement).Assembly
+ };
+ foreach (System.Reflection.Assembly asm in initialAssemblies)
+ assemblyList.OpenAssembly(asm.Location);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ILSpy/Commands/Pdb2XmlCommand.cs b/ILSpy/Commands/Pdb2XmlCommand.cs
index 7258d06f65..fb554c3210 100644
--- a/ILSpy/Commands/Pdb2XmlCommand.cs
+++ b/ILSpy/Commands/Pdb2XmlCommand.cs
@@ -16,7 +16,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
-#if DEBUG
+#if DEBUG && WINDOWS
using System.Collections.Generic;
using System.Composition;
diff --git a/ILSpy/Docking/DockWorkspace.cs b/ILSpy/Docking/DockWorkspace.cs
index 07de6b3e1d..724f1ed63d 100644
--- a/ILSpy/Docking/DockWorkspace.cs
+++ b/ILSpy/Docking/DockWorkspace.cs
@@ -22,19 +22,13 @@
using System.Collections.Specialized;
using System.Composition;
using System.Linq;
-using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
-using System.Windows.Data;
using System.Windows.Threading;
-using AvalonDock;
using AvalonDock.Layout;
-using AvalonDock.Layout.Serialization;
using ICSharpCode.AvalonEdit.Highlighting;
-using ICSharpCode.ILSpy.Analyzers;
-using ICSharpCode.ILSpy.Search;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.ViewModels;
@@ -46,7 +40,7 @@ namespace ICSharpCode.ILSpy.Docking
{
[Export]
[Shared]
- public class DockWorkspace : ObservableObjectBase, ILayoutUpdateStrategy
+ public partial class DockWorkspace : ObservableObjectBase, ILayoutUpdateStrategy
{
private readonly IExportProvider exportProvider;
@@ -55,8 +49,6 @@ public class DockWorkspace : ObservableObjectBase, ILayoutUpdateStrategy
readonly SessionSettings sessionSettings;
- private DockingManager DockingManager => exportProvider.GetExportedValue();
-
public DockWorkspace(SettingsService settingsService, IExportProvider exportProvider)
{
this.exportProvider = exportProvider;
@@ -175,56 +167,6 @@ public TabPageModel ActiveTabPage {
MessageBus.Send(this, new ActiveTabPageChangedEventArgs(value?.GetState()));
}
}
-
- public PaneModel ActivePane {
- get => DockingManager.ActiveContent as PaneModel;
- set => DockingManager.ActiveContent = value;
- }
-
- public void InitializeLayout()
- {
- if (tabPages.Count == 0)
- {
- // Make sure there is at least one tab open
- AddTabPage();
- }
-
- DockingManager.LayoutUpdateStrategy = this;
- XmlLayoutSerializer serializer = new XmlLayoutSerializer(DockingManager);
- serializer.LayoutSerializationCallback += LayoutSerializationCallback;
- try
- {
- sessionSettings.DockLayout.Deserialize(serializer);
- }
- finally
- {
- serializer.LayoutSerializationCallback -= LayoutSerializationCallback;
- }
-
- DockingManager.SetBinding(DockingManager.AnchorablesSourceProperty, new Binding(nameof(ToolPanes)));
- DockingManager.SetBinding(DockingManager.DocumentsSourceProperty, new Binding(nameof(TabPages)));
- }
-
- void LayoutSerializationCallback(object sender, LayoutSerializationCallbackEventArgs e)
- {
- switch (e.Model)
- {
- case LayoutAnchorable la:
- e.Content = this.ToolPanes.FirstOrDefault(p => p.ContentId == la.ContentId);
- e.Cancel = e.Content == null;
- la.CanDockAsTabbedDocument = false;
- if (e.Content is ToolPaneModel toolPaneModel)
- {
- e.Cancel = toolPaneModel.IsVisible;
- toolPaneModel.IsVisible = true;
- }
- break;
- default:
- e.Cancel = true;
- break;
- }
- }
-
public void ShowText(AvalonEditTextOutput textOutput)
{
ActiveTabPage.ShowTextView(textView => textView.ShowText(textOutput));
@@ -252,65 +194,6 @@ internal void CloseAllTabs()
tabPages.RemoveWhere(page => page != activePage);
}
- internal void ResetLayout()
- {
- foreach (var pane in ToolPanes)
- {
- pane.IsVisible = false;
- }
- CloseAllTabs();
- sessionSettings.DockLayout.Reset();
- InitializeLayout();
-
- App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, () => MessageBus.Send(this, new ResetLayoutEventArgs()));
- }
-
- 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)
- {
- }
-
// Dummy property to make the XAML designer happy, the model is provided by the AvalonDock PaneStyleSelectors, not by the DockWorkspace, but the designer assumes the data context in the PaneStyleSelectors is the DockWorkspace.
public PaneModel Model { get; } = null;
}
diff --git a/ILSpy/Docking/DockWorkspace.wpf.cs b/ILSpy/Docking/DockWorkspace.wpf.cs
new file mode 100644
index 0000000000..fddb2e1a3a
--- /dev/null
+++ b/ILSpy/Docking/DockWorkspace.wpf.cs
@@ -0,0 +1,150 @@
+// Copyright (c) 2019 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.
+
+using System.Linq;
+using System.Reflection;
+using System.Windows.Data;
+using System.Windows.Threading;
+
+using AvalonDock;
+using AvalonDock.Layout;
+using AvalonDock.Layout.Serialization;
+
+using ICSharpCode.ILSpy.Analyzers;
+using ICSharpCode.ILSpy.Search;
+using ICSharpCode.ILSpy.ViewModels;
+
+namespace ICSharpCode.ILSpy.Docking
+{
+ ///
+ /// WPF-specific extensions to .
+ ///
+ partial class DockWorkspace
+ {
+ private DockingManager DockingManager => exportProvider.GetExportedValue();
+
+ void LayoutSerializationCallback(object sender, LayoutSerializationCallbackEventArgs e)
+ {
+ switch (e.Model)
+ {
+ case LayoutAnchorable la:
+ e.Content = this.ToolPanes.FirstOrDefault(p => p.ContentId == la.ContentId);
+ e.Cancel = e.Content == null;
+ la.CanDockAsTabbedDocument = false;
+ if (e.Content is ToolPaneModel toolPaneModel)
+ {
+ e.Cancel = toolPaneModel.IsVisible;
+ toolPaneModel.IsVisible = true;
+ }
+ break;
+ default:
+ e.Cancel = true;
+ break;
+ }
+ }
+
+
+ public PaneModel ActivePane {
+ get => DockingManager.ActiveContent as PaneModel;
+ set => DockingManager.ActiveContent = value;
+ }
+
+ public void InitializeLayout()
+ {
+ if (tabPages.Count == 0)
+ {
+ // Make sure there is at least one tab open
+ AddTabPage();
+ }
+
+ DockingManager.LayoutUpdateStrategy = this;
+ XmlLayoutSerializer serializer = new XmlLayoutSerializer(DockingManager);
+ serializer.LayoutSerializationCallback += LayoutSerializationCallback;
+ try
+ {
+ sessionSettings.DockLayout.Deserialize(serializer);
+ }
+ finally
+ {
+ serializer.LayoutSerializationCallback -= LayoutSerializationCallback;
+ }
+
+ DockingManager.SetBinding(DockingManager.AnchorablesSourceProperty, new Binding(nameof(ToolPanes)));
+ DockingManager.SetBinding(DockingManager.DocumentsSourceProperty, new Binding(nameof(TabPages)));
+ }
+
+ internal void ResetLayout()
+ {
+ foreach (var pane in ToolPanes)
+ {
+ pane.IsVisible = false;
+ }
+ CloseAllTabs();
+ sessionSettings.DockLayout.Reset();
+ InitializeLayout();
+
+ App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, () => MessageBus.Send(this, new ResetLayoutEventArgs()));
+ }
+
+ 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)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj
index c68fa53213..f27a6034c5 100644
--- a/ILSpy/ILSpy.csproj
+++ b/ILSpy/ILSpy.csproj
@@ -125,8 +125,8 @@
powershell -NoProfile -ExecutionPolicy Bypass -File BuildTools/sort-resx.ps1
-
-
+
+
diff --git a/ILSpy/ISmartTextOutput.cs b/ILSpy/ISmartTextOutput.cs
index 5ceaff2597..62f283696a 100644
--- a/ILSpy/ISmartTextOutput.cs
+++ b/ILSpy/ISmartTextOutput.cs
@@ -18,13 +18,9 @@
using System;
using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
-using System.Windows.Media;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Decompiler;
-using ICSharpCode.ILSpy.Themes;
namespace ICSharpCode.ILSpy
{
@@ -46,38 +42,4 @@ public interface ISmartTextOutput : ITextOutput
///
string Title { get; set; }
}
-
- public static class SmartTextOutputExtensions
- {
- ///
- /// Creates a button.
- ///
- public static void AddButton(this ISmartTextOutput output, ImageSource icon, string text, RoutedEventHandler click)
- {
- output.AddUIElement(
- delegate {
- Button button = ThemeManager.Current.CreateButton();
- button.Cursor = Cursors.Arrow;
- button.Margin = new Thickness(2);
- button.Padding = new Thickness(9, 1, 9, 1);
- button.MinWidth = 73;
- if (icon != null)
- {
- button.Content = new StackPanel {
- Orientation = Orientation.Horizontal,
- Children = {
- new Image { Width = 16, Height = 16, Source = icon, Margin = new Thickness(0, 0, 4, 0) },
- new TextBlock { Text = text }
- }
- };
- }
- else
- {
- button.Content = text;
- }
- button.Click += click;
- return button;
- });
- }
- }
}
diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs
index 2e0ef396d8..bd8ba2864d 100644
--- a/ILSpy/Languages/CSharpLanguage.cs
+++ b/ILSpy/Languages/CSharpLanguage.cs
@@ -55,7 +55,7 @@ namespace ICSharpCode.ILSpy
///
[Export(typeof(Language))]
[Shared]
- public class CSharpLanguage : Language
+ public partial class CSharpLanguage : Language
{
string name = "C#";
bool showAllMembers = false;
@@ -387,44 +387,6 @@ void AddReferenceAssemblyWarningMessage(MetadataFile module, ITextOutput output)
AddWarningMessage(module, output, line1);
}
- void AddWarningMessage(MetadataFile module, ITextOutput output, string line1, string line2 = null,
- string buttonText = null, System.Windows.Media.ImageSource buttonImage = null, RoutedEventHandler buttonClickHandler = null)
- {
- if (output is ISmartTextOutput fancyOutput)
- {
- string text = line1;
- if (!string.IsNullOrEmpty(line2))
- text += Environment.NewLine + line2;
- fancyOutput.AddUIElement(() => new StackPanel {
- Margin = new Thickness(5),
- Orientation = Orientation.Horizontal,
- Children = {
- new Image {
- Width = 32,
- Height = 32,
- Source = Images.Load(this, "Images/Warning")
- },
- new TextBlock {
- Margin = new Thickness(5, 0, 0, 0),
- Text = text
- }
- }
- });
- fancyOutput.WriteLine();
- if (buttonText != null && buttonClickHandler != null)
- {
- fancyOutput.AddButton(buttonImage, buttonText, buttonClickHandler);
- fancyOutput.WriteLine();
- }
- }
- else
- {
- WriteCommentLine(output, line1);
- if (!string.IsNullOrEmpty(line2))
- WriteCommentLine(output, line2);
- }
- }
-
public override ProjectId DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
{
var module = assembly.GetMetadataFileOrNull();
diff --git a/ILSpy/Languages/CSharpLanguage.wpf.cs b/ILSpy/Languages/CSharpLanguage.wpf.cs
new file mode 100644
index 0000000000..61d378a200
--- /dev/null
+++ b/ILSpy/Languages/CSharpLanguage.wpf.cs
@@ -0,0 +1,75 @@
+// 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.
+
+
+using System;
+using System.Windows;
+using System.Windows.Controls;
+
+using ICSharpCode.Decompiler;
+using ICSharpCode.Decompiler.Metadata;
+
+namespace ICSharpCode.ILSpy
+{
+
+ ///
+ /// C# decompiler integration into ILSpy.
+ /// Note: if you're interested in using the decompiler without the ILSpy UI,
+ /// please directly use the CSharpDecompiler class.
+ ///
+ partial class CSharpLanguage
+ {
+ void AddWarningMessage(MetadataFile module, ITextOutput output, string line1, string line2 = null,
+ string buttonText = null, System.Windows.Media.ImageSource buttonImage = null, RoutedEventHandler buttonClickHandler = null)
+ {
+ if (output is ISmartTextOutput fancyOutput)
+ {
+ string text = line1;
+ if (!string.IsNullOrEmpty(line2))
+ text += Environment.NewLine + line2;
+ fancyOutput.AddUIElement(() => new StackPanel {
+ Margin = new Thickness(5),
+ Orientation = Orientation.Horizontal,
+ Children = {
+ new Image {
+ Width = 32,
+ Height = 32,
+ Source = Images.Load(this, "Images/Warning")
+ },
+ new TextBlock {
+ Margin = new Thickness(5, 0, 0, 0),
+ Text = text
+ }
+ }
+ });
+ fancyOutput.WriteLine();
+ if (buttonText != null && buttonClickHandler != null)
+ {
+ fancyOutput.AddButton(buttonImage, buttonText, buttonClickHandler);
+ fancyOutput.WriteLine();
+ }
+ }
+ else
+ {
+ WriteCommentLine(output, line1);
+ if (!string.IsNullOrEmpty(line2))
+ WriteCommentLine(output, line2);
+ }
+ }
+ }
+}
diff --git a/ILSpy/Metadata/DataDirectoriesTreeNode.cs b/ILSpy/Metadata/DataDirectoriesTreeNode.cs
index 0b5d4f31c0..665258a3d9 100644
--- a/ILSpy/Metadata/DataDirectoriesTreeNode.cs
+++ b/ILSpy/Metadata/DataDirectoriesTreeNode.cs
@@ -36,10 +36,12 @@ public DataDirectoriesTreeNode(PEFile module)
public override object Text => "Data Directories";
public override object NavigationText => $"{Text} ({module.Name})";
-
+#if CROSS_PLATFORM
+ public override object Icon => Images.DirectoryTable;
+#else
public override object Icon => Images.ListFolder;
public override object ExpandedIcon => Images.ListFolderOpen;
-
+#endif
public override bool View(ViewModels.TabPageModel tabPage)
{
tabPage.Title = Text.ToString();
diff --git a/ILSpy/Metadata/DebugDirectoryTreeNode.cs b/ILSpy/Metadata/DebugDirectoryTreeNode.cs
index 6acab3d493..1050cdefc0 100644
--- a/ILSpy/Metadata/DebugDirectoryTreeNode.cs
+++ b/ILSpy/Metadata/DebugDirectoryTreeNode.cs
@@ -41,10 +41,12 @@ public DebugDirectoryTreeNode(PEFile module)
public override object Text => "Debug Directory";
public override object NavigationText => $"{Text} ({module.Name})";
-
+#if CROSS_PLATFORM
+ public override object Icon => Images.DirectoryTable;
+#else
public override object Icon => Images.ListFolder;
public override object ExpandedIcon => Images.ListFolderOpen;
-
+#endif
public override bool View(ViewModels.TabPageModel tabPage)
{
tabPage.Title = Text.ToString();
diff --git a/ILSpy/Metadata/FlagsContentFilter.cs b/ILSpy/Metadata/FlagsContentFilter.cs
new file mode 100644
index 0000000000..1aa8b97aba
--- /dev/null
+++ b/ILSpy/Metadata/FlagsContentFilter.cs
@@ -0,0 +1,22 @@
+using DataGridExtensions;
+
+namespace ICSharpCode.ILSpy.Metadata
+{
+ public class FlagsContentFilter : IContentFilter
+ {
+ public int Mask { get; }
+
+ public FlagsContentFilter(int mask)
+ {
+ this.Mask = mask;
+ }
+
+ public bool IsMatch(object value)
+ {
+ if (value == null)
+ return true;
+
+ return Mask == -1 || (Mask & (int)value) != 0;
+ }
+ }
+}
diff --git a/ILSpy/Metadata/FlagsFilterControl.xaml.cs b/ILSpy/Metadata/FlagsFilterControl.xaml.cs
index 3d81943344..38e8e665be 100644
--- a/ILSpy/Metadata/FlagsFilterControl.xaml.cs
+++ b/ILSpy/Metadata/FlagsFilterControl.xaml.cs
@@ -3,8 +3,6 @@
using System.Windows;
using System.Windows.Controls;
-using DataGridExtensions;
-
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.ILSpy.Metadata
@@ -104,22 +102,4 @@ private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e
Filter = new FlagsContentFilter(mask);
}
}
-
- public class FlagsContentFilter : IContentFilter
- {
- public int Mask { get; }
-
- public FlagsContentFilter(int mask)
- {
- this.Mask = mask;
- }
-
- public bool IsMatch(object value)
- {
- if (value == null)
- return true;
-
- return Mask == -1 || (Mask & (int)value) != 0;
- }
- }
}
diff --git a/ILSpy/Metadata/Helper.wpf.cs b/ILSpy/Metadata/Helper.wpf.cs
new file mode 100644
index 0000000000..c099ce59b2
--- /dev/null
+++ b/ILSpy/Metadata/Helper.wpf.cs
@@ -0,0 +1,43 @@
+using System;
+using System.ComponentModel;
+using System.Reflection;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+
+namespace ICSharpCode.ILSpy.Metadata
+{
+ static partial class Helpers
+ {
+ private static DataTemplate GetOrCreateLinkCellTemplate(string name, PropertyDescriptor descriptor, Binding binding)
+ {
+ if (linkCellTemplates.TryGetValue(name, out var template))
+ {
+ return template;
+ }
+
+ var tb = new FrameworkElementFactory(typeof(TextBlock));
+ var hyper = new FrameworkElementFactory(typeof(Hyperlink));
+ tb.AppendChild(hyper);
+ hyper.AddHandler(Hyperlink.ClickEvent, new RoutedEventHandler(Hyperlink_Click));
+ var run = new FrameworkElementFactory(typeof(Run));
+ hyper.AppendChild(run);
+ run.SetBinding(Run.TextProperty, binding);
+
+ DataTemplate dataTemplate = new DataTemplate() { VisualTree = tb };
+ linkCellTemplates.Add(name, dataTemplate);
+ return dataTemplate;
+
+ void Hyperlink_Click(object sender, RoutedEventArgs e)
+ {
+ var hyperlink = (Hyperlink)sender;
+ var onClickMethod = descriptor.ComponentType.GetMethod("On" + name + "Click", BindingFlags.Instance | BindingFlags.Public);
+ if (onClickMethod != null)
+ {
+ onClickMethod.Invoke(hyperlink.DataContext, Array.Empty