Browse Source

Assembly tree pane scaffolding

Adds the assembly tree pane (DataGrid-based, ProDataGrid hierarchical
rows), the SharpTreeNode-derived node type skeletons it consumes, the
empty MainToolBar placeholder, the ILSpySettings file-path provider
wiring in App.axaml.cs, and the AssemblyTreeModel.Initialize() hook in
the MainWindow code-behind.

Assisted-by: Claude:claude-opus-4-7:Claude Code
pull/3755/head
Siegfried Pammer 2 months ago
parent
commit
08446875cf
  1. 49
      ILSpy.Tests/AssemblyTree/AssemblyTreeModelTests.cs
  2. 22
      ILSpy/App.axaml.cs
  3. 28
      ILSpy/AssemblyTree/AssemblyListPane.axaml
  4. 70
      ILSpy/AssemblyTree/AssemblyListPane.axaml.cs
  5. 79
      ILSpy/AssemblyTree/AssemblyTreeModel.cs
  6. 59
      ILSpy/TreeNodes/AssemblyListTreeNode.cs
  7. 70
      ILSpy/TreeNodes/AssemblyTreeNode.cs
  8. 26
      ILSpy/TreeNodes/ILSpyTreeNode.cs
  9. 33
      ILSpy/TreeNodes/MemberTreeNode.cs
  10. 57
      ILSpy/TreeNodes/NamespaceTreeNode.cs
  11. 80
      ILSpy/TreeNodes/TypeTreeNode.cs
  12. 12
      ILSpy/ViewModels/MainWindowViewModel.cs
  13. 1
      ILSpy/Views/MainWindow.axaml.cs

49
ILSpy.Tests/AssemblyTree/AssemblyTreeModelTests.cs

@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
// Copyright (c) 2026 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 Avalonia.Headless.NUnit;
using AwesomeAssertions;
using ILSpy.AppEnv;
using ILSpy.AssemblyTree;
using NUnit.Framework;
namespace ICSharpCode.ILSpy.Tests.AssemblyTree;
// AssemblyTreeModel is the MEF-shared root of the assembly tree. Initialize() loads
// (or creates) the default assembly list from settings, optionally bootstraps it with
// the three .NET runtime assemblies, and wires Root to an AssemblyListTreeNode. If
// either AssemblyList or Root stays null, the entire pane below is blank — which is
// hard to debug from a UI snapshot, so we catch it at the model layer here.
[TestFixture]
public class AssemblyTreeModelTests
{
[AvaloniaTest]
public void Initialize_populates_AssemblyList_and_Root()
{
var model = AppComposition.Current.GetExport<AssemblyTreeModel>();
model.Should().NotBeNull("AssemblyTreeModel is [Export][Shared] in ILSpy.AssemblyTree.");
model.Initialize();
model.AssemblyList.Should().NotBeNull("Initialize loads or creates the default AssemblyList.");
model.Root.Should().NotBeNull("Initialize wires Root to an AssemblyListTreeNode of the loaded list.");
}
}

22
ILSpy/App.axaml.cs

@ -18,13 +18,16 @@ @@ -18,13 +18,16 @@
using System;
using System.Composition.Hosting;
using System.Diagnostics;
using System.IO;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using ICSharpCode.ILSpyX.Settings;
using ILSpy.AppEnv;
using ILSpy.ViewModels;
using ILSpy.Views;
namespace ILSpy
@ -45,6 +48,23 @@ namespace ILSpy @@ -45,6 +48,23 @@ namespace ILSpy
CommandLineArguments = CommandLineArguments.Create(Environment.GetCommandLineArgs()[1..]);
ILSpySettings.SettingsFilePathProvider = () => {
if (App.CommandLineArguments.ConfigFile != null)
return App.CommandLineArguments.ConfigFile;
var assemblyLocation = typeof(MainWindow).Assembly.Location;
if (!String.IsNullOrWhiteSpace(assemblyLocation))
{
var assemblyDirectory = Path.GetDirectoryName(assemblyLocation);
Debug.Assert(assemblyDirectory != null);
string localPath = Path.Combine(assemblyDirectory, "ILSpy.xml");
if (File.Exists(localPath))
return localPath;
}
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ICSharpCode", "ILSpy.xml");
};
try
{
Composition = AppComposition.Initialize();

28
ILSpy/AssemblyTree/AssemblyListPane.axaml

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:tree="using:ILSpy.AssemblyTree"
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="450"
x:Class="ILSpy.AssemblyTree.AssemblyListPane"
x:DataType="tree:AssemblyTreeModel">
<DataGrid Name="TreeGrid"
HeadersVisibility="None"
HierarchicalRowsEnabled="True"
GridLinesVisibility="None"
IsReadOnly="True"
CanUserResizeColumns="False"
SelectionMode="Single">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Name" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{ReflectionBinding Item.Text}"
VerticalAlignment="Center" Margin="4,0" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</UserControl>

70
ILSpy/AssemblyTree/AssemblyListPane.axaml.cs

@ -0,0 +1,70 @@ @@ -0,0 +1,70 @@
// Copyright (c) 2026 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.Collections;
using System.ComponentModel;
using Avalonia.Controls;
using Avalonia.Controls.DataGridHierarchical;
using ICSharpCode.ILSpyX.TreeView;
namespace ILSpy.AssemblyTree
{
public partial class AssemblyListPane : UserControl
{
public AssemblyListPane()
{
InitializeComponent();
}
protected override void OnDataContextChanged(System.EventArgs e)
{
base.OnDataContextChanged(e);
if (DataContext is AssemblyTreeModel model)
{
model.PropertyChanged += Model_PropertyChanged;
if (model.Root != null)
BindTree(model.Root);
}
}
void Model_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(AssemblyTreeModel.Root) && sender is AssemblyTreeModel model && model.Root != null)
BindTree(model.Root);
}
void BindTree(SharpTreeNode root)
{
var options = new HierarchicalOptions<SharpTreeNode> {
ChildrenSelector = node => node.Children,
IsLeafSelector = node => !node.ShowExpander,
IsExpandedSelector = node => node.IsExpanded,
IsExpandedSetter = (node, val) => node.IsExpanded = val,
AutoExpandRoot = true,
};
var hierarchicalModel = new HierarchicalModel<SharpTreeNode>(options);
hierarchicalModel.SetRoots((IEnumerable)root.Children);
TreeGrid.HierarchicalModel = hierarchicalModel;
}
}
}

79
ILSpy/AssemblyTree/AssemblyTreeModel.cs

@ -0,0 +1,79 @@ @@ -0,0 +1,79 @@
// Copyright (c) 2026 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.Composition;
using CommunityToolkit.Mvvm.ComponentModel;
using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpyX.Settings;
using ICSharpCode.ILSpyX.TreeView;
using ILSpy.TreeNodes;
namespace ILSpy.AssemblyTree
{
[Export]
[Shared]
public partial class AssemblyTreeModel : ObservableObject
{
[ObservableProperty]
private SharpTreeNode? root;
[ObservableProperty]
private SharpTreeNode? selectedItem;
public AssemblyList? AssemblyList { get; private set; }
public void Initialize()
{
var settings = ILSpySettings.Load();
var listManager = new AssemblyListManager(settings);
listManager.CreateDefaultAssemblyLists();
AssemblyList = listManager.LoadList(AssemblyListManager.DefaultListName);
if (AssemblyList.GetAssemblies().Length == 0)
LoadInitialAssemblies(AssemblyList);
var rootNode = new AssemblyListTreeNode(AssemblyList);
rootNode.IsExpanded = true;
Root = rootNode;
}
static void LoadInitialAssemblies(AssemblyList assemblyList)
{
System.Reflection.Assembly[] initialAssemblies = {
typeof(object).Assembly,
typeof(Uri).Assembly,
typeof(System.Linq.Enumerable).Assembly,
};
foreach (var asm in initialAssemblies)
{
if (!string.IsNullOrEmpty(asm.Location))
assemblyList.OpenAssembly(asm.Location);
}
}
public void OpenAssembly(string path)
{
AssemblyList?.Open(path);
}
}
}

59
ILSpy/TreeNodes/AssemblyListTreeNode.cs

@ -0,0 +1,59 @@ @@ -0,0 +1,59 @@
// Copyright (c) 2026 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.Collections.Specialized;
using System.Linq;
using ICSharpCode.ILSpyX;
namespace ILSpy.TreeNodes
{
sealed class AssemblyListTreeNode : ILSpyTreeNode
{
readonly AssemblyList assemblyList;
public AssemblyList AssemblyList => assemblyList;
public AssemblyListTreeNode(AssemblyList assemblyList)
{
ArgumentNullException.ThrowIfNull(assemblyList);
this.assemblyList = assemblyList;
Children.AddRange(assemblyList.GetAssemblies().Select(a => new AssemblyTreeNode(a)));
assemblyList.CollectionChanged += (_, e) => {
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
Children.InsertRange(e.NewStartingIndex, e.NewItems!.Cast<LoadedAssembly>().Select(a => new AssemblyTreeNode(a)));
break;
case NotifyCollectionChangedAction.Remove:
Children.RemoveRange(e.OldStartingIndex, e.OldItems!.Count);
break;
case NotifyCollectionChangedAction.Reset:
Children.Clear();
Children.AddRange(assemblyList.GetAssemblies().Select(a => new AssemblyTreeNode(a)));
break;
}
};
}
public override object Text => assemblyList.ListName;
}
}

70
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -0,0 +1,70 @@ @@ -0,0 +1,70 @@
// Copyright (c) 2026 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.Linq;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpyX;
namespace ILSpy.TreeNodes
{
sealed class AssemblyTreeNode : ILSpyTreeNode
{
readonly LoadedAssembly assembly;
public LoadedAssembly LoadedAssembly => assembly;
public AssemblyTreeNode(LoadedAssembly assembly)
{
ArgumentNullException.ThrowIfNull(assembly);
this.assembly = assembly;
LazyLoading = true;
}
public override object Text => assembly.ShortName;
protected override void LoadChildren()
{
var result = assembly.GetMetadataFileOrNullAsync().Result;
if (result is not MetadataFile module)
return;
var metadata = module.Metadata;
var namespaces = metadata.TypeDefinitions
.Where(t => metadata.GetTypeDefinition(t).GetDeclaringType().IsNil)
.Select(t => metadata.GetString(metadata.GetTypeDefinition(t).Namespace))
.Where(ns => !string.IsNullOrEmpty(ns))
.Distinct()
.OrderBy(ns => ns);
foreach (var ns in namespaces)
Children.Add(new NamespaceTreeNode(ns, module));
var globalTypes = metadata.TypeDefinitions
.Where(t => {
var td = metadata.GetTypeDefinition(t);
return td.GetDeclaringType().IsNil
&& string.IsNullOrEmpty(metadata.GetString(td.Namespace));
});
foreach (var t in globalTypes)
Children.Add(new TypeTreeNode(t, module));
}
}
}

26
ILSpy/TreeNodes/ILSpyTreeNode.cs

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
// Copyright (c) 2026 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 ICSharpCode.ILSpyX.TreeView;
namespace ILSpy.TreeNodes
{
public abstract class ILSpyTreeNode : SharpTreeNode
{
}
}

33
ILSpy/TreeNodes/MemberTreeNode.cs

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
// Copyright (c) 2026 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 ILSpy.TreeNodes
{
sealed class MemberTreeNode : ILSpyTreeNode
{
readonly string name;
public MemberTreeNode(string name)
{
this.name = name;
}
public override object Text => name;
public override bool ShowExpander => false;
}
}

57
ILSpy/TreeNodes/NamespaceTreeNode.cs

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
// Copyright (c) 2026 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.Metadata;
using ICSharpCode.Decompiler.Metadata;
namespace ILSpy.TreeNodes
{
sealed class NamespaceTreeNode : ILSpyTreeNode
{
readonly string name;
readonly MetadataFile module;
public string Name => name;
public NamespaceTreeNode(string name, MetadataFile module)
{
this.name = name;
this.module = module;
LazyLoading = true;
}
public override object Text => name;
protected override void LoadChildren()
{
var metadata = module.Metadata;
var types = metadata.TypeDefinitions
.Where(t => {
var td = metadata.GetTypeDefinition(t);
return td.GetDeclaringType().IsNil
&& metadata.GetString(td.Namespace) == name;
})
.OrderBy(t => metadata.GetString(metadata.GetTypeDefinition(t).Name));
foreach (var t in types)
Children.Add(new TypeTreeNode(t, module));
}
}
}

80
ILSpy/TreeNodes/TypeTreeNode.cs

@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
// Copyright (c) 2026 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.Metadata;
using ICSharpCode.Decompiler.Metadata;
namespace ILSpy.TreeNodes
{
sealed class TypeTreeNode : ILSpyTreeNode
{
readonly TypeDefinitionHandle handle;
readonly MetadataFile module;
public TypeDefinitionHandle Handle => handle;
public MetadataFile Module => module;
public TypeTreeNode(TypeDefinitionHandle handle, MetadataFile module)
{
this.handle = handle;
this.module = module;
LazyLoading = true;
}
public override object Text {
get {
var td = module.Metadata.GetTypeDefinition(handle);
return module.Metadata.GetString(td.Name);
}
}
protected override void LoadChildren()
{
var td = module.Metadata.GetTypeDefinition(handle);
foreach (var nestedType in td.GetNestedTypes())
Children.Add(new TypeTreeNode(nestedType, module));
foreach (var method in td.GetMethods())
{
var md = module.Metadata.GetMethodDefinition(method);
Children.Add(new MemberTreeNode(module.Metadata.GetString(md.Name)));
}
foreach (var field in td.GetFields())
{
var fd = module.Metadata.GetFieldDefinition(field);
Children.Add(new MemberTreeNode(module.Metadata.GetString(fd.Name)));
}
foreach (var prop in td.GetProperties())
{
var pd = module.Metadata.GetPropertyDefinition(prop);
Children.Add(new MemberTreeNode(module.Metadata.GetString(pd.Name)));
}
foreach (var evt in td.GetEvents())
{
var ed = module.Metadata.GetEventDefinition(evt);
Children.Add(new MemberTreeNode(module.Metadata.GetString(ed.Name)));
}
}
}
}

12
ILSpy/ViewModels/MainWindowViewModel.cs

@ -18,16 +18,22 @@ @@ -18,16 +18,22 @@
using System.Composition;
using ILSpy.AssemblyTree;
namespace ILSpy.ViewModels
{
[Export]
[Shared]
public partial class MainWindowViewModel : ViewModelBase
{
public MainWindowViewModel()
{
}
public AssemblyTreeModel AssemblyTreeModel { get; }
public string Title => "ILSpy";
[ImportingConstructor]
public MainWindowViewModel(AssemblyTreeModel assemblyTreeModel)
{
AssemblyTreeModel = assemblyTreeModel;
}
}
}

1
ILSpy/Views/MainWindow.axaml.cs

@ -37,6 +37,7 @@ namespace ILSpy.Views @@ -37,6 +37,7 @@ namespace ILSpy.Views
public MainWindow(MainWindowViewModel viewModel) : this()
{
DataContext = viewModel;
Opened += (_, _) => viewModel.AssemblyTreeModel.Initialize();
}
}
}

Loading…
Cancel
Save