diff --git a/Directory.Packages.props b/Directory.Packages.props
index 41b329b4af..1b73cb5e7c 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -45,7 +45,9 @@
-
-
+
+
+
+
\ No newline at end of file
diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.ruleset b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.ruleset
index 66b1288eb4..61afdc893e 100644
--- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.ruleset
+++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.ruleset
@@ -79,4 +79,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/ILSpy.sln b/ILSpy.sln
index 5d4e13a931..ce506f4d2c 100644
--- a/ILSpy.sln
+++ b/ILSpy.sln
@@ -36,6 +36,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICSharpCode.ILSpyX", "ICSha
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICSharpCode.BamlDecompiler", "ICSharpCode.BamlDecompiler\ICSharpCode.BamlDecompiler.csproj", "{81A30182-3378-4952-8880-F44822390040}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D0858E90-DCD5-4FD9-AA53-7262FAB8BEDB}"
+ ProjectSection(SolutionItems) = preProject
+ .editorconfig = .editorconfig
+ Directory.Packages.props = Directory.Packages.props
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
diff --git a/ILSpy/App.xaml.cs b/ILSpy/App.xaml.cs
index 77722c3ae8..fc74c786d3 100644
--- a/ILSpy/App.xaml.cs
+++ b/ILSpy/App.xaml.cs
@@ -42,6 +42,10 @@
using TomsToolbox.Wpf.Styles;
using ICSharpCode.ILSpyX.TreeView;
+using TomsToolbox.Composition;
+using TomsToolbox.Wpf.Composition;
+using System.ComponentModel.Composition.Hosting;
+
namespace ICSharpCode.ILSpy
{
///
@@ -52,8 +56,7 @@ public partial class App : Application
internal static CommandLineArguments CommandLineArguments;
internal static readonly IList StartupExceptions = new List();
- public static ExportProvider ExportProvider { get; private set; }
- public static IExportProviderFactory ExportProviderFactory { get; private set; }
+ public static IExportProvider ExportProvider { get; private set; }
internal class ExceptionData
{
@@ -89,6 +92,12 @@ public App()
}
TaskScheduler.UnobservedTaskException += DotNet40_UnobservedTaskException;
InitializeMef().GetAwaiter().GetResult();
+
+ // Register the export provider so that it can be accessed from WPF/XAML components.
+ ExportProviderLocator.Register(ExportProvider);
+ // Add data templates registered via MEF.
+ Resources.MergedDictionaries.Add(DataTemplateManager.CreateDynamicDataTemplates(ExportProvider));
+
Languages.Initialize(ExportProvider);
EventManager.RegisterClassHandler(typeof(Window),
Hyperlink.RequestNavigateEvent,
@@ -170,8 +179,9 @@ private static async Task InitializeMef()
// If/When any part needs to import ICompositionService, this will be needed:
// catalog.WithCompositionService();
var config = CompositionConfiguration.Create(catalog);
- ExportProviderFactory = config.CreateExportProviderFactory();
- ExportProvider = ExportProviderFactory.CreateExportProvider();
+ var exportProviderFactory = config.CreateExportProviderFactory();
+ ExportProvider = new ExportProviderAdapter(exportProviderFactory.CreateExportProvider());
+
// This throws exceptions for composition failures. Alternatively, the configuration's CompositionErrors property
// could be used to log the errors directly. Used at the end so that it does not prevent the export provider setup.
config.ThrowOnErrors();
diff --git a/ILSpy/ContextMenuEntry.cs b/ILSpy/ContextMenuEntry.cs
index 9ce4416a2a..fcbdb1bae9 100644
--- a/ILSpy/ContextMenuEntry.cs
+++ b/ILSpy/ContextMenuEntry.cs
@@ -31,6 +31,8 @@
using ICSharpCode.ILSpy.Controls.TreeView;
using ICSharpCode.ILSpyX.TreeView;
+using TomsToolbox.Composition;
+
namespace ICSharpCode.ILSpy
{
public interface IContextMenuEntry
@@ -205,7 +207,7 @@ public static void Add(DataGrid dataGrid)
readonly DecompilerTextView textView;
readonly ListBox listBox;
readonly DataGrid dataGrid;
- readonly Lazy[] entries;
+ readonly IExport[] entries;
private ContextMenuProvider()
{
@@ -288,8 +290,8 @@ void dataGrid_ContextMenuOpening(object sender, ContextMenuEventArgs e)
bool ShowContextMenu(TextViewContext context, out ContextMenu menu)
{
menu = new ContextMenu();
- var menuGroups = new Dictionary[]>();
- Lazy[] topLevelGroup = null;
+ var menuGroups = new Dictionary[]>();
+ IExport[] topLevelGroup = null;
foreach (var group in entries.OrderBy(c => c.Metadata.Order).GroupBy(c => c.Metadata.ParentMenuID))
{
if (group.Key == null)
@@ -301,10 +303,10 @@ bool ShowContextMenu(TextViewContext context, out ContextMenu menu)
menuGroups.Add(group.Key, group.ToArray());
}
}
- BuildMenu(topLevelGroup ?? Array.Empty>(), menu.Items);
+ BuildMenu(topLevelGroup ?? Array.Empty>(), menu.Items);
return menu.Items.Count > 0;
- void BuildMenu(Lazy[] menuGroup, ItemCollection parent)
+ void BuildMenu(IExport[] menuGroup, ItemCollection parent)
{
foreach (var category in menuGroup.GroupBy(c => c.Metadata.Category))
{
diff --git a/ILSpy/ExportProviderAdapter.cs b/ILSpy/ExportProviderAdapter.cs
new file mode 100644
index 0000000000..555352fc46
--- /dev/null
+++ b/ILSpy/ExportProviderAdapter.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+
+using Microsoft.VisualStudio.Composition;
+
+using TomsToolbox.Composition;
+using TomsToolbox.Essentials;
+
+namespace ICSharpCode.ILSpy;
+
+#nullable enable
+
+///
+/// Adapter for Microsoft.VisualStudio.Composition. to .
+///
+public class ExportProviderAdapter : IExportProvider
+{
+ private static readonly Type DefaultMetadataType = typeof(Dictionary);
+
+ private readonly ExportProvider _exportProvider;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The export provider.
+ public ExportProviderAdapter(ExportProvider exportProvider)
+ {
+ _exportProvider = exportProvider;
+ }
+
+ event EventHandler? IExportProvider.ExportsChanged { add { } remove { } }
+
+ T IExportProvider.GetExportedValue(string? contractName) where T : class
+ {
+ return _exportProvider.GetExportedValue(contractName) ?? throw new InvalidOperationException($"No export found for type {typeof(T).FullName} with contract '{contractName}'");
+ }
+
+ T? IExportProvider.GetExportedValueOrDefault(string? contractName) where T : class
+ {
+ return _exportProvider.GetExportedValues(contractName).SingleOrDefault();
+ }
+
+#pragma warning disable CS8769 // Nullability of reference types in type of parameter doesn't match implemented member (possibly because of nullability attributes).
+ // can't apply NotNullWhen here, because ICSharpCode.Decompiler defines a duplicate attribute, and uses InternalsVisibleTo("ILSpy"), so this attribute is now ambiguous!
+ bool IExportProvider.TryGetExportedValue(string? contractName, /*[NotNullWhen(true)]*/ out T? value) where T : class
+#pragma warning restore CS8769 // Nullability of reference types in type of parameter doesn't match implemented member (possibly because of nullability attributes).
+ {
+ value = _exportProvider.GetExportedValues(contractName).SingleOrDefault();
+
+ return !Equals(value, default(T));
+ }
+
+ IEnumerable IExportProvider.GetExportedValues(string? contractName) where T : class
+ {
+ return _exportProvider.GetExportedValues(contractName);
+ }
+
+ IEnumerable