Browse Source

Basic work to add AvalonDock using MVVM, avoiding too big changes to existing architecture for now

pull/1801/head
Andreas Weizel 6 years ago
parent
commit
56b9401a49
  1. 16
      ILSpy/Analyzers/AnalyzeCommand.cs
  2. 21
      ILSpy/Analyzers/AnalyzerTreeView.cs
  3. 5
      ILSpy/Commands/DecompileInNewViewCommand.cs
  4. 4
      ILSpy/Commands/ShowDebugSteps.cs
  5. 6
      ILSpy/DebugSteps.xaml.cs
  6. 25
      ILSpy/Docking/ActiveDocumentConverter.cs
  7. 2
      ILSpy/Docking/DockLayoutSettings.cs
  8. 47
      ILSpy/Docking/DockWorkspace.cs
  9. 50
      ILSpy/Docking/DockingHelper.cs
  10. 42
      ILSpy/Docking/LayoutUpdateStrategy.cs
  11. 43
      ILSpy/Docking/PaneCollection.cs
  12. 2
      ILSpy/Docking/PanePosition.cs
  13. 24
      ILSpy/Docking/PaneStyleSelector.cs
  14. 25
      ILSpy/Docking/PaneTemplateSelector.cs
  15. 13
      ILSpy/ILSpy.csproj
  16. 140
      ILSpy/MainWindow.xaml
  17. 78
      ILSpy/MainWindow.xaml.cs
  18. 17
      ILSpy/Search/SearchPane.cs
  19. 15
      ILSpy/ViewModels/AnalyzerPaneModel.cs
  20. 16
      ILSpy/ViewModels/AssemblyListPaneModel.cs
  21. 15
      ILSpy/ViewModels/DebugStepsPaneModel.cs
  22. 12
      ILSpy/ViewModels/DocumentModel.cs
  23. 80
      ILSpy/ViewModels/PaneModel.cs
  24. 16
      ILSpy/ViewModels/SearchPaneModel.cs
  25. 7
      ILSpy/ViewModels/ToolPaneModel.cs

16
ILSpy/Analyzers/AnalyzeCommand.cs

@ -58,17 +58,17 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -58,17 +58,17 @@ namespace ICSharpCode.ILSpy.Analyzers
{
if (context.SelectedTreeNodes != null) {
foreach (IMemberTreeNode node in context.SelectedTreeNodes) {
AnalyzerTreeView.Instance.Analyze(node.Member);
MainWindow.Instance.AnalyzerTreeView.Analyze(node.Member);
}
} else if (context.Reference != null && context.Reference.Reference is IEntity entity) {
AnalyzerTreeView.Instance.Analyze(entity);
MainWindow.Instance.AnalyzerTreeView.Analyze(entity);
}
}
public override bool CanExecute(object parameter)
{
if (AnalyzerTreeView.Instance.IsKeyboardFocusWithin) {
return AnalyzerTreeView.Instance.SelectedItems.OfType<object>().All(n => n is IMemberTreeNode);
if (MainWindow.Instance.AnalyzerTreeView.IsKeyboardFocusWithin) {
return MainWindow.Instance.AnalyzerTreeView.SelectedItems.OfType<object>().All(n => n is IMemberTreeNode);
} else {
return MainWindow.Instance.SelectedNodes.All(n => n is IMemberTreeNode);
}
@ -76,13 +76,13 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -76,13 +76,13 @@ namespace ICSharpCode.ILSpy.Analyzers
public override void Execute(object parameter)
{
if (AnalyzerTreeView.Instance.IsKeyboardFocusWithin) {
foreach (IMemberTreeNode node in AnalyzerTreeView.Instance.SelectedItems.OfType<IMemberTreeNode>().ToArray()) {
AnalyzerTreeView.Instance.Analyze(node.Member);
if (MainWindow.Instance.AnalyzerTreeView.IsKeyboardFocusWithin) {
foreach (IMemberTreeNode node in MainWindow.Instance.AnalyzerTreeView.SelectedItems.OfType<IMemberTreeNode>().ToArray()) {
MainWindow.Instance.AnalyzerTreeView.Analyze(node.Member);
}
} else {
foreach (IMemberTreeNode node in MainWindow.Instance.SelectedNodes) {
AnalyzerTreeView.Instance.Analyze(node.Member);
MainWindow.Instance.AnalyzerTreeView.Analyze(node.Member);
}
}
}

21
ILSpy/Analyzers/AnalyzerTreeView.cs

@ -23,6 +23,8 @@ using System.Linq; @@ -23,6 +23,8 @@ using System.Linq;
using System.Windows;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.Analyzers.TreeNodes;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.TreeView;
namespace ICSharpCode.ILSpy.Analyzers
@ -32,21 +34,7 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -32,21 +34,7 @@ namespace ICSharpCode.ILSpy.Analyzers
/// </summary>
public class AnalyzerTreeView : SharpTreeView, IPane
{
static AnalyzerTreeView instance;
public static AnalyzerTreeView Instance
{
get
{
if (instance == null) {
App.Current.VerifyAccess();
instance = new AnalyzerTreeView();
}
return instance;
}
}
private AnalyzerTreeView()
public AnalyzerTreeView()
{
this.ShowRoot = false;
this.Root = new AnalyzerRootNode { Language = MainWindow.Instance.CurrentLanguage };
@ -72,8 +60,7 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -72,8 +60,7 @@ namespace ICSharpCode.ILSpy.Analyzers
public void Show()
{
if (!IsVisible)
MainWindow.Instance.ShowInNewPane("Analyzer", this, PanePosition.Bottom);
DockWorkspace.Instance.ToolPanes.Add(AnalyzerPaneModel.Instance);
}
public void Show(AnalyzerTreeNode node)

5
ILSpy/Commands/DecompileInNewViewCommand.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System.Linq;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes;
@ -45,7 +46,9 @@ namespace ICSharpCode.ILSpy.Commands @@ -45,7 +46,9 @@ namespace ICSharpCode.ILSpy.Commands
var dtv = new DecompilerTextView();
var nodes = context.SelectedTreeNodes.Cast<ILSpyTreeNode>().ToArray();
var title = string.Join(", ", nodes.Select(x => x.ToString()));
MainWindow.Instance.ShowInNewPane(title, dtv, PanePosition.Document);
// TODO
//MainWindow.Instance.ShowInNewPane(title, dtv, PanePosition.Document);
//DockWorkspace.Instance.Documents.Add(new ViewModels.DocumentModel() { Title = title });
await dtv.DecompileAsync(MainWindow.Instance.CurrentLanguage, nodes, new DecompilationOptions());
}
}

4
ILSpy/Commands/ShowDebugSteps.cs

@ -1,6 +1,8 @@ @@ -1,6 +1,8 @@
#if DEBUG
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy.Commands
{
@ -9,7 +11,7 @@ namespace ICSharpCode.ILSpy.Commands @@ -9,7 +11,7 @@ namespace ICSharpCode.ILSpy.Commands
{
public override void Execute(object parameter)
{
DebugSteps.Show();
DockWorkspace.Instance.ToolPanes.Add(DebugStepsPaneModel.Instance);
}
}
}

6
ILSpy/DebugSteps.xaml.cs

@ -4,6 +4,8 @@ using System.Windows.Controls; @@ -4,6 +4,8 @@ using System.Windows.Controls;
using System.Windows.Input;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy
{
@ -20,7 +22,7 @@ namespace ICSharpCode.ILSpy @@ -20,7 +22,7 @@ namespace ICSharpCode.ILSpy
ILAstLanguage language;
#endif
DebugSteps()
public DebugSteps()
{
InitializeComponent();
@ -79,7 +81,7 @@ namespace ICSharpCode.ILSpy @@ -79,7 +81,7 @@ namespace ICSharpCode.ILSpy
public static void Show()
{
MainWindow.Instance.ShowInNewPane(Properties.Resources.DebugSteps, new DebugSteps(), PanePosition.Top);
DockWorkspace.Instance.ToolPanes.Add(DebugStepsPaneModel.Instance);
}
void IPane.Closed()

25
ILSpy/Docking/ActiveDocumentConverter.cs

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
using System;
using System.Windows.Data;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy.Docking
{
public class ActiveDocumentConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is DocumentModel)
return value;
return Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is DocumentModel)
return value;
return Binding.DoNothing;
}
}
}

2
ILSpy/Docking/DockLayoutSettings.cs

@ -32,7 +32,7 @@ namespace ICSharpCode.ILSpy.Docking @@ -32,7 +32,7 @@ namespace ICSharpCode.ILSpy.Docking
public void Deserialize(XmlLayoutSerializer serializer)
{
if (!Valid)
return;
rawSettings = "<LayoutRoot />";
using (StringReader reader = new StringReader(rawSettings)) {
serializer.Deserialize(reader);

47
ILSpy/Docking/DockWorkspace.cs

@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
using System.Collections.ObjectModel;
using System.ComponentModel;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy.Docking
{
public class DockWorkspace : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public static DockWorkspace Instance { get; } = new DockWorkspace();
private DockWorkspace()
{
Documents.Add(new DocumentModel());
ToolPanes.Add(AssemblyListPaneModel.Instance);
}
public PaneCollection<DocumentModel> Documents { get; } = new PaneCollection<DocumentModel>();
public PaneCollection<ToolPaneModel> ToolPanes { get; } = new PaneCollection<ToolPaneModel>();
public void Remove(PaneModel model)
{
Documents.Remove(model as DocumentModel);
ToolPanes.Remove(model as ToolPaneModel);
}
private DocumentModel _activeDocument = null;
public DocumentModel ActiveDocument {
get {
return _activeDocument;
}
set {
if (_activeDocument != value) {
_activeDocument = value;
RaisePropertyChanged(nameof(ActiveDocument));
}
}
}
protected void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

50
ILSpy/Docking/DockingHelper.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Windows;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Xceed.Wpf.AvalonDock.Layout;
@ -6,7 +7,18 @@ namespace ICSharpCode.ILSpy.Docking @@ -6,7 +7,18 @@ namespace ICSharpCode.ILSpy.Docking
{
public static class DockingHelper
{
public static void DockHorizontal(LayoutContent layoutContent, ILayoutElement paneRelativeTo, GridLength dockHeight, bool dockBefore = false)
public static bool Dock(LayoutRoot root, LayoutContent layoutContent, PanePosition position)
{
var documentPane = root.Descendents().OfType<LayoutDocumentPane>().FirstOrDefault();
if ((position == PanePosition.Top) || (position == PanePosition.Bottom)) {
return DockHorizontal(layoutContent, documentPane, new GridLength(200), position == PanePosition.Top);
} else if ((position == PanePosition.Left) || (position == PanePosition.Right)) {
return DockVertical(layoutContent as LayoutAnchorable, documentPane, new GridLength(400), position == PanePosition.Left);
}
return false;
}
public static bool DockHorizontal(LayoutContent layoutContent, ILayoutElement paneRelativeTo, GridLength dockHeight, bool dockBefore = false)
{
if (paneRelativeTo is ILayoutDocumentPane parentDocumentPane) {
var parentDocumentGroup = paneRelativeTo.FindParent<LayoutDocumentPaneGroup>();
@ -22,11 +34,39 @@ namespace ICSharpCode.ILSpy.Docking @@ -22,11 +34,39 @@ namespace ICSharpCode.ILSpy.Docking
parentDocumentGroup.InsertChildAt(dockBefore ? indexOfParentPane : indexOfParentPane + 1, layoutDocumentPane);
layoutContent.IsActive = true;
layoutContent.Root.CollectGarbage();
Application.Current.MainWindow.Dispatcher.Invoke(() => {
Application.Current.MainWindow.Dispatcher.Invoke(
() => layoutDocumentPane.DockHeight = dockHeight,
System.Windows.Threading.DispatcherPriority.Loaded);
return true;
}
return false;
}
public static bool DockVertical(LayoutAnchorable anchorable, ILayoutElement paneRelativeTo, GridLength dockWidth, bool dockBefore = false)
{
if (paneRelativeTo is ILayoutDocumentPane parentDocumentPane) {
var grandParent = parentDocumentPane.Parent as LayoutPanel;
var targetAnchorablePane = grandParent.Children.OfType<LayoutAnchorablePane>().FirstOrDefault();
if (targetAnchorablePane == null) {
targetAnchorablePane = new LayoutAnchorablePane() {
DockWidth = new GridLength(400)
};
int targetIndex = dockBefore ? 0 : grandParent.ChildrenCount;
grandParent.InsertChildAt(targetIndex, targetAnchorablePane);
}
grandParent.Orientation = Orientation.Horizontal;
targetAnchorablePane.Children.Add(anchorable);
layoutDocumentPane.DockHeight = dockHeight;
}, System.Windows.Threading.DispatcherPriority.Loaded);
anchorable.IsActive = true;
anchorable.Root.CollectGarbage();
Application.Current.MainWindow.Dispatcher.Invoke(
() => targetAnchorablePane.DockWidth = dockWidth,
System.Windows.Threading.DispatcherPriority.Loaded);
return true;
}
return false;
}
}
}

42
ILSpy/Docking/LayoutUpdateStrategy.cs

@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
using System.Linq;
using System.Windows;
using ICSharpCode.ILSpy.ViewModels;
using Xceed.Wpf.AvalonDock.Layout;
namespace ICSharpCode.ILSpy.Docking
{
public class LayoutUpdateStrategy : ILayoutUpdateStrategy
{
public bool BeforeInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableToShow, ILayoutContainer destinationContainer)
{
if ((destinationContainer != null) &&
(destinationContainer.FindParent<LayoutFloatingWindow>() != null))
return false;
PanePosition targetPosition = PanePosition.Top;
switch (anchorableToShow.Content) {
case AnalyzerPaneModel _:
targetPosition = PanePosition.Bottom;
break;
case AssemblyListPaneModel _:
targetPosition = PanePosition.Left;
break;
}
return DockingHelper.Dock(layout, anchorableToShow, targetPosition);
}
public void AfterInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableShown)
{
}
public bool BeforeInsertDocument(LayoutRoot layout, LayoutDocument anchorableToShow, ILayoutContainer destinationContainer)
{
return false;
}
public void AfterInsertDocument(LayoutRoot layout, LayoutDocument anchorableShown)
{
}
}
}

43
ILSpy/Docking/PaneCollection.cs

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy.Docking
{
public class PaneCollection<T> : INotifyCollectionChanged, INotifyPropertyChanged, ICollection<T>
where T : PaneModel
{
private ObservableCollection<T> observableCollection = new ObservableCollection<T>();
public event NotifyCollectionChangedEventHandler CollectionChanged;
public event PropertyChangedEventHandler PropertyChanged;
public PaneCollection()
{
observableCollection.CollectionChanged += (sender, e) => CollectionChanged?.Invoke(this, e);
}
public void Add(T item)
{
if (!this.Any(pane => pane.ContentId == item.ContentId)) {
observableCollection.Add(item);
}
item.IsVisible = true;
item.IsActive = true;
}
public int Count => observableCollection.Count();
public bool IsReadOnly => false;
public void Clear() => observableCollection.Clear();
public bool Contains(T item) => observableCollection.Contains(item);
public void CopyTo(T[] array, int arrayIndex) => observableCollection.CopyTo(array, arrayIndex);
public bool Remove(T item) => observableCollection.Remove(item);
public IEnumerator<T> GetEnumerator() => observableCollection.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => observableCollection.GetEnumerator();
}
}

2
ILSpy/Docking/PanePosition.cs

@ -4,6 +4,8 @@ @@ -4,6 +4,8 @@
{
Top,
Bottom,
Left,
Right,
Document
}
}

24
ILSpy/Docking/PaneStyleSelector.cs

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
using System.Windows;
using System.Windows.Controls;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy.Docking
{
public class PaneStyleSelector : StyleSelector
{
public Style ToolPaneStyle { get; set; }
public Style DocumentStyle { get; set; }
public override Style SelectStyle(object item, DependencyObject container)
{
if (item is DocumentModel)
return DocumentStyle;
if (item is ToolPaneModel)
return ToolPaneStyle;
return base.SelectStyle(item, container);
}
}
}

25
ILSpy/Docking/PaneTemplateSelector.cs

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
namespace ICSharpCode.ILSpy.Docking
{
public class TemplateMapping
{
public Type Type { get; set; }
public DataTemplate Template { get; set; }
}
public class PaneTemplateSelector : DataTemplateSelector
{
public Collection<TemplateMapping> Mappings { get; set; } = new Collection<TemplateMapping>();
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
return Mappings.FirstOrDefault(m => m.Type == item.GetType())?.Template
?? base.SelectTemplate(item, container);
}
}
}

13
ILSpy/ILSpy.csproj

@ -138,8 +138,20 @@ @@ -138,8 +138,20 @@
<Compile Include="DebugSteps.xaml.cs">
<DependentUpon>DebugSteps.xaml</DependentUpon>
</Compile>
<Compile Include="Docking\ActiveDocumentConverter.cs" />
<Compile Include="ViewModels\AssemblyListPaneModel.cs" />
<Compile Include="Docking\DockingHelper.cs" />
<Compile Include="Docking\DockLayoutSettings.cs" />
<Compile Include="ViewModels\DocumentModel.cs" />
<Compile Include="Docking\LayoutUpdateStrategy.cs" />
<Compile Include="Docking\PaneCollection.cs" />
<Compile Include="ViewModels\PaneModel.cs" />
<Compile Include="Docking\PaneStyleSelector.cs" />
<Compile Include="Docking\PaneTemplateSelector.cs" />
<Compile Include="ViewModels\DebugStepsPaneModel.cs" />
<Compile Include="ViewModels\AnalyzerPaneModel.cs" />
<Compile Include="ViewModels\SearchPaneModel.cs" />
<Compile Include="ViewModels\ToolPaneModel.cs" />
<Compile Include="ILSpyTraceListener.cs" />
<Compile Include="DecompilationOptions.cs" />
<Compile Include="ExtensionMethods.cs" />
@ -252,6 +264,7 @@ @@ -252,6 +264,7 @@
<Compile Include="TreeNodes\ResourceNodes\XmlResourceNode.cs" />
<Compile Include="TreeNodes\SearchMsdnContextMenuEntry.cs" />
<Compile Include="Analyzers\Builtin\TypeExtensionMethodsAnalyzer.cs" />
<Compile Include="Docking\DockWorkspace.cs" />
<EmbeddedResource Include="..\doc\LGPL.txt">
<Link>LGPL.txt</Link>
</EmbeddedResource>

140
ILSpy/MainWindow.xaml

@ -5,8 +5,11 @@ @@ -5,8 +5,11 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:tv="clr-namespace:ICSharpCode.TreeView;assembly=ICSharpCode.TreeView"
xmlns:local="clr-namespace:ICSharpCode.ILSpy"
xmlns:avalondock="http://schemas.xceed.com/wpf/xaml/avalondock"
xmlns:docking="clr-namespace:ICSharpCode.ILSpy.Docking"
xmlns:controls="clr-namespace:ICSharpCode.ILSpy.Controls"
xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties"
xmlns:analyzers="clr-namespace:ICSharpCode.ILSpy.Analyzers"
xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties"
xmlns:viewmodels="clr-namespace:ICSharpCode.ILSpy.ViewModels"
Title="ILSpy"
MinWidth="250"
MinHeight="200"
@ -18,7 +21,46 @@ @@ -18,7 +21,46 @@
>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<docking:ActiveDocumentConverter x:Key="ActiveDocumentConverter"/>
<tv:SharpTreeView x:Key="TreeView"
AutomationProperties.Name="Assemblies and Classes"
SelectionChanged="TreeView_SelectionChanged"
ShowRoot="False"
AllowDropOrder="True"
AllowDrop="True"
BorderThickness="0,1,1,1" Visibility="Visible" />
<DataTemplate x:Key="AssemblyListPaneTemplate">
<ContentControl Content="{StaticResource TreeView}" />
</DataTemplate>
<local:DebugSteps x:Key="DebugSteps" />
<DataTemplate x:Key="DebugStepsPaneTemplate">
<ContentControl Content="{StaticResource DebugSteps}" />
</DataTemplate>
<local:SearchPane x:Key="SearchPane" />
<DataTemplate x:Key="SearchPaneTemplate">
<ContentControl Content="{StaticResource SearchPane}" />
</DataTemplate>
<analyzers:AnalyzerTreeView x:Key="AnalyzerTreeView" />
<DataTemplate x:Key="AnalyzerPaneTemplate">
<ContentControl Content="{StaticResource AnalyzerTreeView}" />
</DataTemplate>
<ContentPresenter x:Key="MainPane" />
<DataTemplate x:Key="DecompilerTextViewTemplate">
<!-- decompilerTextView is inserted into the mainPane by code -->
<ContentControl Content="{StaticResource MainPane}" />
</DataTemplate>
</Window.Resources>
<Window.CommandBindings>
<CommandBinding
Command="Open"
@ -54,9 +96,9 @@ @@ -54,9 +96,9 @@
<MenuItem Header="{x:Static properties:Resources._File}" />
<!-- contents of file menu are added using MEF -->
<MenuItem Header="{x:Static properties:Resources._View}">
<MenuItem Header="{x:Static properties:Resources.Show_publiconlyTypesMembers}" IsCheckable="True" IsChecked="{Binding FilterSettings.ApiVisPublicOnly}" />
<MenuItem Header="{x:Static properties:Resources.Show_internalTypesMembers}" IsCheckable="True" IsChecked="{Binding FilterSettings.ApiVisPublicAndInternal}" />
<MenuItem Header="{x:Static properties:Resources.Show_allTypesAndMembers}" IsCheckable="True" IsChecked="{Binding FilterSettings.ApiVisAll}" />
<MenuItem Header="{x:Static properties:Resources.Show_publiconlyTypesMembers}" IsCheckable="True" IsChecked="{Binding SessionSettings.FilterSettings.ApiVisPublicOnly}" />
<MenuItem Header="{x:Static properties:Resources.Show_internalTypesMembers}" IsCheckable="True" IsChecked="{Binding SessionSettings.FilterSettings.ApiVisPublicAndInternal}" />
<MenuItem Header="{x:Static properties:Resources.Show_allTypesAndMembers}" IsCheckable="True" IsChecked="{Binding SessionSettings.FilterSettings.ApiVisAll}" />
</MenuItem>
</Menu>
<!-- ToolBar -->
@ -79,23 +121,23 @@ @@ -79,23 +121,23 @@
<Separator />
<!-- 'Open' toolbar category is inserted here -->
<Separator />
<CheckBox IsChecked="{Binding FilterSettings.ApiVisPublicOnly}" ToolTip="{x:Static properties:Resources.ShowPublicOnlyTypesMembers}">
<CheckBox IsChecked="{Binding SessionSettings.FilterSettings.ApiVisPublicOnly}" ToolTip="{x:Static properties:Resources.ShowPublicOnlyTypesMembers}">
<Image Width="16" Height="16" Source="{controls:XamlResource Images/ShowPublicOnly}" />
</CheckBox>
<CheckBox IsChecked="{Binding FilterSettings.ApiVisPublicAndInternal}" ToolTip="{x:Static properties:Resources.ShowInternalTypesMembers}">
<CheckBox IsChecked="{Binding SessionSettings.FilterSettings.ApiVisPublicAndInternal}" ToolTip="{x:Static properties:Resources.ShowInternalTypesMembers}">
<Image Width="16" Height="16" Source="{controls:XamlResource Images/ShowPrivateInternal}" />
</CheckBox>
<CheckBox IsChecked="{Binding FilterSettings.ApiVisAll}" ToolTip="{x:Static properties:Resources.ShowAllTypesAndMembers}">
<CheckBox IsChecked="{Binding SessionSettings.FilterSettings.ApiVisAll}" ToolTip="{x:Static properties:Resources.ShowAllTypesAndMembers}">
<Image Width="16" Height="16" Source="{controls:XamlResource Images/ShowAll}" />
</CheckBox>
<Separator />
<ComboBox Name="languageComboBox" DisplayMemberPath="Name" Width="100" MaxDropDownHeight="Auto"
ItemsSource="{x:Static local:Languages.AllLanguages}" ToolTip="{x:Static properties:Resources.SelectLanguageDropdownTooltip}"
SelectedItem="{Binding FilterSettings.Language}"/>
SelectedItem="{Binding SessionSettings.FilterSettings.Language}"/>
<ComboBox Name="languageVersionComboBox" DisplayMemberPath="DisplayName" Width="120" MaxDropDownHeight="Auto" ToolTip="{x:Static properties:Resources.SelectVersionDropdownTooltip}"
Visibility="{Binding SelectedItem.HasLanguageVersions, ElementName=languageComboBox, Converter={StaticResource BooleanToVisibilityConverter}}"
ItemsSource="{Binding SelectedItem.LanguageVersions, ElementName=languageComboBox, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding FilterSettings.LanguageVersion, UpdateSourceTrigger=PropertyChanged}"/>
SelectedItem="{Binding SessionSettings.FilterSettings.LanguageVersion, UpdateSourceTrigger=PropertyChanged}"/>
</ToolBar>
<Border DockPanel.Dock="Top" BorderBrush="Black" BorderThickness="1" Name="updatePanel" Visibility="Collapsed">
<DockPanel KeyboardNavigation.TabNavigation="Contained">
@ -116,41 +158,61 @@ @@ -116,41 +158,61 @@
Text="{x:Static properties:Resources.StandBy}"/>
</StatusBarItem>
</StatusBar>
<!-- Main grid separating left pane (treeView) from main pane (textEditor) -->
<avalondock:DockingManager x:Name="DockManager"
AllowMixedOrientation="True" Grid.ColumnSpan="2">
<avalondock:LayoutRoot x:Name="LayoutRoot" >
<avalondock:LayoutPanel Orientation="Vertical">
<avalondock:LayoutPanel Orientation="Horizontal">
<avalondock:LayoutAnchorablePaneGroup DockWidth="400" Orientation="Vertical">
<avalondock:LayoutAnchorablePane DockHeight="*">
<avalondock:LayoutAnchorable x:Name="Tree" Title="Assemblies" CanHide="False" CanClose="False">
<!-- Left pane: Tree View of assemblies and classes -->
<tv:SharpTreeView
Name="treeView"
AutomationProperties.Name="Assemblies and Classes"
SelectionChanged="TreeView_SelectionChanged"
ShowRoot="False"
AllowDropOrder="True"
AllowDrop="True"
BorderThickness="0,1,1,1" Visibility="Visible" />
</avalondock:LayoutAnchorable>
</avalondock:LayoutAnchorablePane>
</avalondock:LayoutAnchorablePaneGroup>
DataContext="{Binding Workspace}"
AnchorablesSource="{Binding ToolPanes}"
DocumentsSource="{Binding Documents}"
ActiveContent="{Binding ActiveDocument, Mode=Default, Converter={StaticResource ActiveDocumentConverter}}"
AllowMixedOrientation="True">
<avalondock:LayoutDocumentPaneGroup DockWidth="*">
<avalondock:LayoutDocumentPane x:Name="adDocumentPane">
<avalondock:LayoutDocument Title="View" CanClose="False">
<!-- decompilerTextView is into the mainPane by code -->
<ContentPresenter Name="mainPane" />
</avalondock:LayoutDocument>
</avalondock:LayoutDocumentPane>
</avalondock:LayoutDocumentPaneGroup>
</avalondock:LayoutPanel>
<avalondock:LayoutRoot>
<avalondock:LayoutPanel Orientation="Vertical">
<avalondock:LayoutDocumentPane />
</avalondock:LayoutPanel>
</avalondock:LayoutRoot>
<avalondock:DockingManager.LayoutUpdateStrategy>
<docking:LayoutUpdateStrategy />
</avalondock:DockingManager.LayoutUpdateStrategy>
<avalondock:DockingManager.LayoutItemTemplateSelector>
<docking:PaneTemplateSelector>
<docking:PaneTemplateSelector.Mappings>
<docking:TemplateMapping Type="{x:Type viewmodels:AssemblyListPaneModel}" Template="{StaticResource AssemblyListPaneTemplate}" />
<docking:TemplateMapping Type="{x:Type viewmodels:SearchPaneModel}" Template="{StaticResource SearchPaneTemplate}" />
<docking:TemplateMapping Type="{x:Type viewmodels:DebugStepsPaneModel}" Template="{StaticResource DebugStepsPaneTemplate}" />
<docking:TemplateMapping Type="{x:Type viewmodels:AnalyzerPaneModel}" Template="{StaticResource AnalyzerPaneTemplate}" />
<docking:TemplateMapping Type="{x:Type viewmodels:DocumentModel}" Template="{StaticResource DecompilerTextViewTemplate}" />
</docking:PaneTemplateSelector.Mappings>
</docking:PaneTemplateSelector>
</avalondock:DockingManager.LayoutItemTemplateSelector>
<avalondock:DockingManager.LayoutItemContainerStyleSelector>
<docking:PaneStyleSelector>
<docking:PaneStyleSelector.ToolPaneStyle>
<Style TargetType="{x:Type avalondock:LayoutAnchorableItem}">
<Setter Property="Title" Value="{Binding Model.Title}"/>
<Setter Property="Visibility" Value="{Binding Model.IsVisible, Mode=TwoWay, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter={x:Static Visibility.Hidden}}"/>
<Setter Property="ContentId" Value="{Binding Model.ContentId}"/>
<Setter Property="IsSelected" Value="{Binding Model.IsSelected, Mode=TwoWay}"/>
<Setter Property="IsActive" Value="{Binding Model.IsActive, Mode=TwoWay}"/>
<Setter Property="CanClose" Value="{Binding Model.IsCloseable, Mode=TwoWay}" />
<Setter Property="CanHide" Value="{Binding Model.IsCloseable}" />
</Style>
</docking:PaneStyleSelector.ToolPaneStyle>
<docking:PaneStyleSelector.DocumentStyle>
<Style TargetType="{x:Type avalondock:LayoutItem}">
<Setter Property="Title" Value="{Binding Model.Title}"/>
<Setter Property="Visibility" Value="{Binding Model.IsVisible, Mode=TwoWay, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter={x:Static Visibility.Hidden}}"/>
<Setter Property="ContentId" Value="{Binding Model.ContentId}"/>
<Setter Property="IsSelected" Value="{Binding Model.IsSelected, Mode=TwoWay}"/>
<Setter Property="IsActive" Value="{Binding Model.IsActive, Mode=TwoWay}"/>
<Setter Property="CanClose" Value="{Binding Model.IsCloseable, Mode=TwoWay}" />
</Style>
</docking:PaneStyleSelector.DocumentStyle>
</docking:PaneStyleSelector>
</avalondock:DockingManager.LayoutItemContainerStyleSelector>
</avalondock:DockingManager>
</DockPanel>
</Window>

78
ILSpy/MainWindow.xaml.cs

@ -38,9 +38,12 @@ using ICSharpCode.Decompiler.Documentation; @@ -38,9 +38,12 @@ using ICSharpCode.Decompiler.Documentation;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.ILSpy.Analyzers;
using ICSharpCode.ILSpy.Controls;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.TreeView;
using Microsoft.Win32;
using OSVersionHelper;
@ -49,6 +52,12 @@ using Xceed.Wpf.AvalonDock.Layout.Serialization; @@ -49,6 +52,12 @@ using Xceed.Wpf.AvalonDock.Layout.Serialization;
namespace ICSharpCode.ILSpy
{
class MainWindowDataContext
{
public DockWorkspace Workspace { get; set; }
public SessionSettings SessionSettings { get; set; }
}
/// <summary>
/// The main window of the application.
/// </summary>
@ -76,6 +85,30 @@ namespace ICSharpCode.ILSpy @@ -76,6 +85,30 @@ namespace ICSharpCode.ILSpy
get { return sessionSettings; }
}
public ContentPresenter mainPane {
get {
return FindResource("MainPane") as ContentPresenter;
}
}
public SharpTreeView treeView {
get {
return FindResource("TreeView") as SharpTreeView;
}
}
public AnalyzerTreeView AnalyzerTreeView {
get {
return FindResource("AnalyzerTreeView") as AnalyzerTreeView;
}
}
public SearchPane SearchPane {
get {
return FindResource("SearchPane") as SearchPane;
}
}
public MainWindow()
{
instance = this;
@ -86,9 +119,13 @@ namespace ICSharpCode.ILSpy @@ -86,9 +119,13 @@ namespace ICSharpCode.ILSpy
this.Icon = new BitmapImage(new Uri("pack://application:,,,/ILSpy;component/images/ILSpy.ico"));
this.DataContext = sessionSettings;
this.DataContext = new MainWindowDataContext {
Workspace = DockWorkspace.Instance,
SessionSettings = sessionSettings
};
InitializeComponent();
decompilerTextView = App.ExportProvider.GetExportedValue<DecompilerTextView>();
mainPane.Content = decompilerTextView;
@ -295,8 +332,8 @@ namespace ICSharpCode.ILSpy @@ -295,8 +332,8 @@ namespace ICSharpCode.ILSpy
commandLineLoadedAssemblies.Clear(); // clear references once we don't need them anymore
NavigateOnLaunch(args.NavigateTo, sessionSettings.ActiveTreeViewPath, spySettings, relevantAssemblies);
if (args.Search != null) {
SearchPane.Instance.SearchTerm = args.Search;
SearchPane.Instance.Show();
SearchPane.SearchTerm = args.Search;
SearchPane.Show();
}
}
@ -877,7 +914,7 @@ namespace ICSharpCode.ILSpy @@ -877,7 +914,7 @@ namespace ICSharpCode.ILSpy
void SearchCommandExecuted(object sender, ExecutedRoutedEventArgs e)
{
SearchPane.Instance.Show();
DockWorkspace.Instance.ToolPanes.Add(SearchPaneModel.Instance);
}
#endregion
@ -1037,22 +1074,22 @@ namespace ICSharpCode.ILSpy @@ -1037,22 +1074,22 @@ namespace ICSharpCode.ILSpy
return loadedAssy.FileName;
}
#region Top/Bottom Pane management
//#region Top/Bottom Pane management
public void ShowInNewPane(string title, object content, PanePosition panePosition, string toolTip = null)
{
if (panePosition == PanePosition.Document) {
var layoutDocument = new LayoutDocument() { Title = title, Content = content, ToolTip = toolTip, CanClose = true };
var documentPane = this.DockManager.Layout.Descendents().OfType<LayoutDocumentPane>().FirstOrDefault();
documentPane.Children.Add(layoutDocument);
} else {
var layoutAnchorable = new LayoutAnchorable() { Title = title, Content = content, ToolTip = toolTip, CanClose = true, CanHide = true };
var documentPane = this.DockManager.Layout.Descendents().OfType<LayoutDocumentPane>().FirstOrDefault();
Docking.DockingHelper.DockHorizontal(layoutAnchorable, documentPane, new GridLength(200), panePosition == PanePosition.Top);
}
}
//public void ShowInNewPane(string title, object content, PanePosition panePosition, string toolTip = null)
//{
// if (panePosition == PanePosition.Document) {
// var layoutDocument = new LayoutDocument() { Title = title, Content = content, ToolTip = toolTip, CanClose = true };
// var documentPane = this.DockManager.Layout.Descendents().OfType<LayoutDocumentPane>().FirstOrDefault();
// documentPane.Children.Add(layoutDocument);
// } else {
// var layoutAnchorable = new LayoutAnchorable() { Title = title, Content = content, ToolTip = toolTip, CanClose = true, CanHide = true };
// var documentPane = this.DockManager.Layout.Descendents().OfType<LayoutDocumentPane>().FirstOrDefault();
// Docking.DockingHelper.DockHorizontal(layoutAnchorable, documentPane, new GridLength(200), panePosition == PanePosition.Top);
// }
//}
#endregion
//#endregion
public void UnselectAll()
{
@ -1076,5 +1113,10 @@ namespace ICSharpCode.ILSpy @@ -1076,5 +1113,10 @@ namespace ICSharpCode.ILSpy
{
return toolBar.Items;
}
private void DockManager_DocumentClosed(object sender, Xceed.Wpf.AvalonDock.DocumentClosedEventArgs e)
{
}
}
}

17
ILSpy/Search/SearchPane.cs

@ -31,7 +31,9 @@ using System.Windows.Input; @@ -31,7 +31,9 @@ using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.Search;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy
{
@ -42,7 +44,6 @@ namespace ICSharpCode.ILSpy @@ -42,7 +44,6 @@ namespace ICSharpCode.ILSpy
{
const int MAX_RESULTS = 1000;
const int MAX_REFRESH_TIME_MS = 10; // More means quicker forward of data, less means better responsibility
static SearchPane instance;
RunningSearch currentSearch;
bool runSearchOnNextShow;
@ -53,17 +54,7 @@ namespace ICSharpCode.ILSpy @@ -53,17 +54,7 @@ namespace ICSharpCode.ILSpy
get { return (ObservableCollection<SearchResult>)GetValue(ResultsProperty); }
}
public static SearchPane Instance {
get {
if (instance == null) {
App.Current.VerifyAccess();
instance = new SearchPane();
}
return instance;
}
}
private SearchPane()
public SearchPane()
{
InitializeComponent();
searchModeComboBox.Items.Add(new { Image = Images.Library, Name = "Types and Members" });
@ -114,7 +105,7 @@ namespace ICSharpCode.ILSpy @@ -114,7 +105,7 @@ namespace ICSharpCode.ILSpy
public void Show()
{
if (!IsVisible) {
MainWindow.Instance.ShowInNewPane(Properties.Resources.SearchPane_Search, this, PanePosition.Top);
DockWorkspace.Instance.ToolPanes.Add(SearchPaneModel.Instance);
if (runSearchOnNextShow) {
runSearchOnNextShow = false;
StartSearch(this.SearchTerm);

15
ILSpy/ViewModels/AnalyzerPaneModel.cs

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
namespace ICSharpCode.ILSpy.ViewModels
{
public class AnalyzerPaneModel : ToolPaneModel
{
public const string PaneContentId = "analyzerPane";
public static AnalyzerPaneModel Instance { get; } = new AnalyzerPaneModel();
private AnalyzerPaneModel()
{
ContentId = PaneContentId;
Title = Properties.Resources.Analyze;
}
}
}

16
ILSpy/ViewModels/AssemblyListPaneModel.cs

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
namespace ICSharpCode.ILSpy.ViewModels
{
public class AssemblyListPaneModel : ToolPaneModel
{
public const string PaneContentId = "assemblyListPane";
public static AssemblyListPaneModel Instance { get; } = new AssemblyListPaneModel();
private AssemblyListPaneModel()
{
Title = "Assemblies";
ContentId = PaneContentId;
IsCloseable = false;
}
}
}

15
ILSpy/ViewModels/DebugStepsPaneModel.cs

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
namespace ICSharpCode.ILSpy.ViewModels
{
public class DebugStepsPaneModel : ToolPaneModel
{
public const string PaneContentId = "debugStepsPane";
public static DebugStepsPaneModel Instance { get; } = new DebugStepsPaneModel();
private DebugStepsPaneModel()
{
ContentId = PaneContentId;
Title = Properties.Resources.DebugSteps;
}
}
}

12
ILSpy/ViewModels/DocumentModel.cs

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
namespace ICSharpCode.ILSpy.ViewModels
{
public class DocumentModel : PaneModel
{
public DocumentModel()
{
ContentId = "document";
Title = "View";
IsCloseable = false;
}
}
}

80
ILSpy/ViewModels/PaneModel.cs

@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
using System.ComponentModel;
namespace ICSharpCode.ILSpy.ViewModels
{
public class PaneModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private bool isSelected = false;
public bool IsSelected {
get => isSelected;
set {
if (isSelected != value) {
isSelected = value;
RaisePropertyChanged(nameof(IsSelected));
}
}
}
private bool isActive = false;
public bool IsActive {
get => isActive;
set {
if (isActive != value) {
isActive = value;
RaisePropertyChanged(nameof(IsActive));
}
}
}
private bool isVisible = true;
public bool IsVisible {
get { return isVisible; }
set {
if (isVisible != value) {
isVisible = value;
RaisePropertyChanged(nameof(IsVisible));
}
}
}
private bool isCloseable = true;
public bool IsCloseable {
get { return isCloseable; }
set {
if (isCloseable != value) {
isCloseable = value;
RaisePropertyChanged(nameof(IsCloseable));
}
}
}
private string contentId;
public string ContentId {
get => contentId;
set {
if (contentId != value) {
contentId = value;
RaisePropertyChanged(nameof(ContentId));
}
}
}
private string title;
public string Title {
get => title;
set {
if (title != value) {
title = value;
RaisePropertyChanged(nameof(Title));
}
}
}
}
}

16
ILSpy/ViewModels/SearchPaneModel.cs

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
namespace ICSharpCode.ILSpy.ViewModels
{
public class SearchPaneModel : ToolPaneModel
{
public const string PaneContentId = "searchPane";
public static SearchPaneModel Instance { get; } = new SearchPaneModel();
private SearchPaneModel()
{
ContentId = PaneContentId;
Title = Properties.Resources.SearchPane_Search;
IsCloseable = true;
}
}
}

7
ILSpy/ViewModels/ToolPaneModel.cs

@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
namespace ICSharpCode.ILSpy.ViewModels
{
public class ToolPaneModel : PaneModel
{
}
}
Loading…
Cancel
Save