Browse Source

Remove more code from MainWindow, refactor startup sequence

pull/3274/head
tom-englert 1 year ago committed by tom-englert
parent
commit
39b036b027
  1. 5
      ICSharpCode.ILSpyX/AssemblyListManager.cs
  2. 48
      ICSharpCode.ILSpyX/Settings/ILSpySettings.cs
  3. 7
      ICSharpCode.ILSpyX/Settings/ISettingsProvider.cs
  4. 4
      ICSharpCode.ILSpyX/Settings/MiscSettings.cs
  5. 1
      ILSpy.ReadyToRun/ReadyToRunDisassembler.cs
  6. 25
      ILSpy.ReadyToRun/ReadyToRunOptions.cs
  7. 4
      ILSpy/AboutPage.cs
  8. 17
      ILSpy/App.xaml
  9. 48
      ILSpy/App.xaml.cs
  10. 105
      ILSpy/AssemblyTree/AssemblyListPaneModel.cs
  11. 2
      ILSpy/Commands/CheckForUpdatesCommand.cs
  12. 7
      ILSpy/Docking/DockWorkspace.cs
  13. 3
      ILSpy/ILSpy.csproj
  14. 3
      ILSpy/Languages/Languages.cs
  15. 113
      ILSpy/MainWindow.xaml
  16. 143
      ILSpy/MainWindow.xaml.cs
  17. 2
      ILSpy/Options/MiscSettingsPanel.xaml
  18. 30
      ILSpy/Options/MiscSettingsPanel.xaml.cs
  19. 67
      ILSpy/Options/MiscSettingsViewModel.cs
  20. 15
      ILSpy/Options/OptionsDialog.xaml.cs
  21. 6
      ILSpy/SessionSettings.cs
  22. 2
      ILSpy/Updates/UpdateSettings.cs
  23. 18
      ILSpy/Util/SettingsService.cs

5
ICSharpCode.ILSpyX/AssemblyListManager.cs

@ -39,7 +39,7 @@ namespace ICSharpCode.ILSpyX @@ -39,7 +39,7 @@ namespace ICSharpCode.ILSpyX
public const string DotNet35List = ".NET 3.5";
public const string ASPDotNetMVC3List = "ASP.NET (MVC3)";
private ISettingsProvider settingsProvider;
private readonly ISettingsProvider settingsProvider;
public AssemblyListManager(ISettingsProvider settingsProvider)
{
@ -69,14 +69,13 @@ namespace ICSharpCode.ILSpyX @@ -69,14 +69,13 @@ namespace ICSharpCode.ILSpyX
/// </summary>
public AssemblyList LoadList(string listName)
{
this.settingsProvider = this.settingsProvider.Load();
AssemblyList list = DoLoadList(listName);
if (!AssemblyLists.Contains(list.ListName))
AssemblyLists.Add(list.ListName);
return list;
}
AssemblyList DoLoadList(string listName)
AssemblyList DoLoadList(string? listName)
{
XElement doc = this.settingsProvider["AssemblyLists"];
if (listName != null)

48
ICSharpCode.ILSpyX/Settings/ILSpySettings.cs

@ -34,16 +34,11 @@ namespace ICSharpCode.ILSpyX.Settings @@ -34,16 +34,11 @@ namespace ICSharpCode.ILSpyX.Settings
/// </summary>
public static ISettingsFilePathProvider? SettingsFilePathProvider { get; set; }
readonly XElement root;
XElement root;
ILSpySettings()
ILSpySettings(XElement? root = null)
{
this.root = new XElement("ILSpy");
}
ILSpySettings(XElement root)
{
this.root = root;
this.root = root ?? new XElement("ILSpy");
}
public XElement this[XName section] {
@ -64,13 +59,7 @@ namespace ICSharpCode.ILSpyX.Settings @@ -64,13 +59,7 @@ namespace ICSharpCode.ILSpyX.Settings
{
try
{
XDocument doc = LoadWithoutCheckingCharacters(GetConfigFile());
if (null == doc.Root)
{
return new ILSpySettings();
}
return new ILSpySettings(doc.Root);
return new ILSpySettings(LoadFile(GetConfigFile()).Root);
}
catch (IOException)
{
@ -83,7 +72,7 @@ namespace ICSharpCode.ILSpyX.Settings @@ -83,7 +72,7 @@ namespace ICSharpCode.ILSpyX.Settings
}
}
static XDocument LoadWithoutCheckingCharacters(string fileName)
static XDocument LoadFile(string fileName)
{
return XDocument.Load(fileName, LoadOptions.None);
}
@ -91,16 +80,15 @@ namespace ICSharpCode.ILSpyX.Settings @@ -91,16 +80,15 @@ namespace ICSharpCode.ILSpyX.Settings
/// <summary>
/// Saves a setting section.
/// </summary>
public static void SaveSettings(XElement section)
public void SaveSettings(XElement section)
{
Update(
delegate (XElement root) {
XElement? existingElement = root.Element(section.Name);
if (existingElement != null)
existingElement.ReplaceWith(section);
else
root.Add(section);
});
Update(rootElement => {
XElement? existingElement = rootElement.Element(section.Name);
if (existingElement != null)
existingElement.ReplaceWith(section);
else
rootElement.Add(section);
});
}
/// <summary>
@ -108,7 +96,7 @@ namespace ICSharpCode.ILSpyX.Settings @@ -108,7 +96,7 @@ namespace ICSharpCode.ILSpyX.Settings
/// We always reload the file on updates to ensure we aren't overwriting unrelated changes performed
/// by another ILSpy instance.
/// </summary>
public static void Update(Action<XElement> action)
public void Update(Action<XElement> action)
{
using (new MutexProtector(ConfigFileMutex))
{
@ -116,7 +104,7 @@ namespace ICSharpCode.ILSpyX.Settings @@ -116,7 +104,7 @@ namespace ICSharpCode.ILSpyX.Settings
XDocument doc;
try
{
doc = LoadWithoutCheckingCharacters(config);
doc = LoadFile(config);
}
catch (IOException)
{
@ -131,6 +119,7 @@ namespace ICSharpCode.ILSpyX.Settings @@ -131,6 +119,7 @@ namespace ICSharpCode.ILSpyX.Settings
doc.Root!.SetAttributeValue("version", DecompilerVersionInfo.Major + "." + DecompilerVersionInfo.Minor + "." + DecompilerVersionInfo.Build + "." + DecompilerVersionInfo.Revision);
action(doc.Root);
doc.Save(config, SaveOptions.None);
this.root = doc.Root;
}
}
@ -148,11 +137,6 @@ namespace ICSharpCode.ILSpyX.Settings @@ -148,11 +137,6 @@ namespace ICSharpCode.ILSpyX.Settings
// return "ILSpy.xml";
}
ISettingsProvider ISettingsProvider.Load()
{
return Load();
}
const string ConfigFileMutex = "01A91708-49D1-410D-B8EB-4DE2662B3971";
/// <summary>

7
ICSharpCode.ILSpyX/Settings/ISettingsProvider.cs

@ -22,8 +22,6 @@ using System.Linq; @@ -22,8 +22,6 @@ using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using static System.Collections.Specialized.BitVector32;
namespace ICSharpCode.ILSpyX.Settings
{
public interface ISettingsProvider
@ -31,9 +29,8 @@ namespace ICSharpCode.ILSpyX.Settings @@ -31,9 +29,8 @@ namespace ICSharpCode.ILSpyX.Settings
XElement this[XName section] { get; }
void Update(Action<XElement> action);
ISettingsProvider Load();
public static ICSharpCode.Decompiler.DecompilerSettings LoadDecompilerSettings(ISettingsProvider settingsProvider)
public static Decompiler.DecompilerSettings LoadDecompilerSettings(ISettingsProvider settingsProvider)
{
XElement e = settingsProvider["DecompilerSettings"];
var newSettings = new Decompiler.DecompilerSettings();
@ -48,7 +45,7 @@ namespace ICSharpCode.ILSpyX.Settings @@ -48,7 +45,7 @@ namespace ICSharpCode.ILSpyX.Settings
return newSettings;
}
public static void SaveDecompilerSettings(XElement root, ICSharpCode.Decompiler.DecompilerSettings newSettings)
public static void SaveDecompilerSettings(XElement root, Decompiler.DecompilerSettings newSettings)
{
var properties = typeof(Decompiler.DecompilerSettings).GetProperties()
.Where(p => p.GetCustomAttribute<BrowsableAttribute>()?.Browsable != false);

4
ICSharpCode.ILSpyX/Settings/MiscSettings.cs

@ -23,12 +23,12 @@ namespace ICSharpCode.ILSpyX.Settings @@ -23,12 +23,12 @@ namespace ICSharpCode.ILSpyX.Settings
{
public class MiscSettings : IMiscSettings, ISettingsSection<MiscSettings>
{
private MiscSettings()
public MiscSettings()
{
}
public bool AllowMultipleInstances { get; set; }
public bool LoadPreviousAssemblies { get; set; }
public bool LoadPreviousAssemblies { get; set; } = true;
public static MiscSettings Load(ISettingsProvider settingsProvider)
{

1
ILSpy.ReadyToRun/ReadyToRunDisassembler.cs

@ -26,6 +26,7 @@ using Iced.Intel; @@ -26,6 +26,7 @@ using Iced.Intel;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpy.Util;
using ILCompiler.Reflection.ReadyToRun;
using ILCompiler.Reflection.ReadyToRun.Amd64;

25
ILSpy.ReadyToRun/ReadyToRunOptions.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System.Xml.Linq;
using ICSharpCode.ILSpy.Util;
using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpyX.Settings;
@ -33,10 +34,8 @@ namespace ICSharpCode.ILSpy.ReadyToRun @@ -33,10 +34,8 @@ namespace ICSharpCode.ILSpy.ReadyToRun
public static string GetDisassemblyFormat(ILSpySettings settings)
{
if (settings == null)
{
settings = ILSpySettings.Load();
}
settings ??= SettingsService.Instance.SpySettings;
XElement e = settings[ns + "ReadyToRunOptions"];
XAttribute a = e.Attribute("DisassemblyFormat");
if (a == null)
@ -51,10 +50,8 @@ namespace ICSharpCode.ILSpy.ReadyToRun @@ -51,10 +50,8 @@ namespace ICSharpCode.ILSpy.ReadyToRun
public static bool GetIsShowUnwindInfo(ILSpySettings settings)
{
if (settings == null)
{
settings = ILSpySettings.Load();
}
settings ??= SettingsService.Instance.SpySettings;
XElement e = settings[ns + "ReadyToRunOptions"];
XAttribute a = e.Attribute("IsShowUnwindInfo");
@ -70,10 +67,8 @@ namespace ICSharpCode.ILSpy.ReadyToRun @@ -70,10 +67,8 @@ namespace ICSharpCode.ILSpy.ReadyToRun
public static bool GetIsShowDebugInfo(ILSpySettings settings)
{
if (settings == null)
{
settings = ILSpySettings.Load();
}
settings ??= SettingsService.Instance.SpySettings;
XElement e = settings[ns + "ReadyToRunOptions"];
XAttribute a = e.Attribute("IsShowDebugInfo");
@ -89,10 +84,8 @@ namespace ICSharpCode.ILSpy.ReadyToRun @@ -89,10 +84,8 @@ namespace ICSharpCode.ILSpy.ReadyToRun
public static bool GetIsShowGCInfo(ILSpySettings settings)
{
if (settings == null)
{
settings = ILSpySettings.Load();
}
settings ??= SettingsService.Instance.SpySettings;
XElement e = settings[ns + "ReadyToRunOptions"];
XAttribute a = e.Attribute("IsShowGCInfo");

4
ILSpy/AboutPage.cs

@ -42,7 +42,7 @@ namespace ICSharpCode.ILSpy @@ -42,7 +42,7 @@ namespace ICSharpCode.ILSpy
{
public override void Execute(object parameter)
{
MainWindow.Instance.NavigateTo(
MainWindow.Instance.AssemblyTreeModel.NavigateTo(
new RequestNavigateEventArgs(new Uri("resource://aboutpage"), null),
inNewTabPage: true
);
@ -76,7 +76,7 @@ namespace ICSharpCode.ILSpy @@ -76,7 +76,7 @@ namespace ICSharpCode.ILSpy
CheckBox checkBox = new CheckBox();
checkBox.Margin = new Thickness(4);
checkBox.Content = Resources.AutomaticallyCheckUpdatesEveryWeek;
UpdateSettings settings = new UpdateSettings(ILSpySettings.Load());
UpdateSettings settings = new UpdateSettings(SettingsService.Instance.SpySettings);
checkBox.SetBinding(CheckBox.IsCheckedProperty, new Binding("AutomaticUpdateCheckEnabled") { Source = settings });
return new StackPanel {
Margin = new Thickness(0, 4, 0, 0),

17
ILSpy/App.xaml

@ -1,15 +1,14 @@ @@ -1,15 +1,14 @@
<Application x:Class="ICSharpCode.ILSpy.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:styles="urn:TomsToolbox.Wpf.Styles"
xmlns:toms="urn:TomsToolbox"
xmlns:themes="clr-namespace:ICSharpCode.ILSpy.Themes"
StartupUri="MainWindow.xaml">
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:styles="urn:TomsToolbox.Wpf.Styles"
xmlns:toms="urn:TomsToolbox"
xmlns:themes="clr-namespace:ICSharpCode.ILSpy.Themes">
<Application.Resources>
<Style x:Key="DialogWindow" TargetType="{x:Type Window}">
<Setter Property="ShowInTaskbar" Value="False"/>
<Setter Property="UseLayoutRounding" Value="True"/>
<Setter Property="TextOptions.TextFormattingMode" Value="Display"/>
<Setter Property="ShowInTaskbar" Value="False" />
<Setter Property="UseLayoutRounding" Value="True" />
<Setter Property="TextOptions.TextFormattingMode" Value="Display" />
<Setter Property="toms:StyleBindings.Behaviors">
<Setter.Value>
<toms:BehaviorCollection>

48
ILSpy/App.xaml.cs

@ -31,6 +31,7 @@ using System.Windows.Navigation; @@ -31,6 +31,7 @@ using System.Windows.Navigation;
using System.Windows.Threading;
using ICSharpCode.ILSpy.AppEnv;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Options;
using ICSharpCode.ILSpyX.Analyzers;
using ICSharpCode.ILSpyX.Settings;
@ -44,7 +45,6 @@ using ICSharpCode.ILSpyX.TreeView; @@ -44,7 +45,6 @@ using ICSharpCode.ILSpyX.TreeView;
using TomsToolbox.Composition;
using TomsToolbox.Wpf.Composition;
using System.ComponentModel.Composition.Hosting;
namespace ICSharpCode.ILSpy
{
@ -69,15 +69,7 @@ namespace ICSharpCode.ILSpy @@ -69,15 +69,7 @@ namespace ICSharpCode.ILSpy
ILSpySettings.SettingsFilePathProvider = new ILSpySettingsFilePathProvider();
var cmdArgs = Environment.GetCommandLineArgs().Skip(1);
App.CommandLineArguments = CommandLineArguments.Create(cmdArgs);
bool forceSingleInstance = (App.CommandLineArguments.SingleInstance ?? true)
&& !MiscSettingsPanel.CurrentMiscSettings.AllowMultipleInstances;
if (forceSingleInstance)
{
SingleInstance.Attach(); // will auto-exit for second instance
SingleInstance.NewInstanceDetected += SingleInstance_NewInstanceDetected;
}
CommandLineArguments = CommandLineArguments.Create(cmdArgs);
SharpTreeNode.SetImagesProvider(new WpfWindowsTreeNodeImagesProvider());
@ -85,7 +77,7 @@ namespace ICSharpCode.ILSpy @@ -85,7 +77,7 @@ namespace ICSharpCode.ILSpy
Resources.RegisterDefaultStyles();
if (!System.Diagnostics.Debugger.IsAttached)
if (!Debugger.IsAttached)
{
AppDomain.CurrentDomain.UnhandledException += ShowErrorBox;
Dispatcher.CurrentDispatcher.UnhandledException += Dispatcher_UnhandledException;
@ -93,6 +85,14 @@ namespace ICSharpCode.ILSpy @@ -93,6 +85,14 @@ namespace ICSharpCode.ILSpy
TaskScheduler.UnobservedTaskException += DotNet40_UnobservedTaskException;
InitializeMef().GetAwaiter().GetResult();
bool forceSingleInstance = (CommandLineArguments.SingleInstance ?? true)
&& !SettingsService.Instance.MiscSettings.AllowMultipleInstances;
if (forceSingleInstance)
{
SingleInstance.Attach(); // will auto-exit for second instance
SingleInstance.NewInstanceDetected += SingleInstance_NewInstanceDetected;
}
// Register the export provider so that it can be accessed from WPF/XAML components.
ExportProviderLocator.Register(ExportProvider);
// Add data templates registered via MEF.
@ -103,24 +103,19 @@ namespace ICSharpCode.ILSpy @@ -103,24 +103,19 @@ namespace ICSharpCode.ILSpy
new RequestNavigateEventHandler(Window_RequestNavigate));
ILSpyTraceListener.Install();
if (App.CommandLineArguments.ArgumentsParser.IsShowingInformation)
if (CommandLineArguments.ArgumentsParser.IsShowingInformation)
{
MessageBox.Show(App.CommandLineArguments.ArgumentsParser.GetHelpText(), "ILSpy Command Line Arguments");
MessageBox.Show(CommandLineArguments.ArgumentsParser.GetHelpText(), "ILSpy Command Line Arguments");
}
if (App.CommandLineArguments.ArgumentsParser.RemainingArguments.Any())
if (CommandLineArguments.ArgumentsParser.RemainingArguments.Any())
{
string unknownArguments = string.Join(", ", App.CommandLineArguments.ArgumentsParser.RemainingArguments);
string unknownArguments = string.Join(", ", CommandLineArguments.ArgumentsParser.RemainingArguments);
MessageBox.Show(unknownArguments, "ILSpy Unknown Command Line Arguments Passed");
}
}
private static void SingleInstance_NewInstanceDetected(object sender, NewInstanceEventArgs e)
{
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
ICSharpCode.ILSpy.MainWindow.Instance.HandleSingleInstanceCommandLineArguments(e.Args);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
}
private static void SingleInstance_NewInstanceDetected(object sender, NewInstanceEventArgs e) => ExportProvider.GetExportedValue<AssemblyListPaneModel>().HandleSingleInstanceCommandLineArguments(e.Args).HandleExceptions();
static Assembly ResolvePluginDependencies(AssemblyLoadContext context, AssemblyName assemblyName)
{
@ -200,6 +195,8 @@ namespace ICSharpCode.ILSpy @@ -200,6 +195,8 @@ namespace ICSharpCode.ILSpy
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var output = new StringBuilder();
if (StartupExceptions.FormatExceptions(output))
@ -207,7 +204,12 @@ namespace ICSharpCode.ILSpy @@ -207,7 +204,12 @@ namespace ICSharpCode.ILSpy
MessageBox.Show(output.ToString(), "Sorry we crashed!");
Environment.Exit(1);
}
base.OnStartup(e);
MainWindow = new MainWindow();
MainWindow.Loaded += (sender, args) => {
ExportProvider.GetExportedValue<AssemblyListPaneModel>().Initialize();
};
MainWindow.Show();
}
void DotNet40_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
@ -268,7 +270,7 @@ namespace ICSharpCode.ILSpy @@ -268,7 +270,7 @@ namespace ICSharpCode.ILSpy
void Window_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
ILSpy.MainWindow.Instance.NavigateTo(e);
ExportProvider.GetExportedValue<AssemblyListPaneModel>().NavigateTo(e);
}
}
}

105
ILSpy/AssemblyTree/AssemblyListPaneModel.cs

@ -53,6 +53,7 @@ using System.Text; @@ -53,6 +53,7 @@ using System.Text;
using TomsToolbox.Essentials;
using TomsToolbox.Wpf;
using System.Windows.Navigation;
namespace ICSharpCode.ILSpy.AssemblyTree
{
@ -151,6 +152,26 @@ namespace ICSharpCode.ILSpy.AssemblyTree @@ -151,6 +152,26 @@ namespace ICSharpCode.ILSpy.AssemblyTree
}
}
public async Task HandleSingleInstanceCommandLineArguments(string[] args)
{
var cmdArgs = CommandLineArguments.Create(args);
await Dispatcher.InvokeAsync(() => {
if (!HandleCommandLineArguments(cmdArgs))
return;
var window = Application.Current.MainWindow;
if (!cmdArgs.NoActivate && window is { WindowState: WindowState.Minimized })
{
window.WindowState = WindowState.Normal;
}
HandleCommandLineArgumentsAfterShowList(cmdArgs);
});
}
public async void NavigateOnLaunch(string navigateTo, string[] activeTreeViewPath, ILSpySettings spySettings, List<LoadedAssembly> relevantAssemblies)
{
var initialSelection = SelectedItem;
@ -315,22 +336,11 @@ namespace ICSharpCode.ILSpy.AssemblyTree @@ -315,22 +336,11 @@ namespace ICSharpCode.ILSpy.AssemblyTree
public void Initialize()
{
var loadPreviousAssemblies = Options.MiscSettingsPanel.CurrentMiscSettings.LoadPreviousAssemblies;
var sessionSettings = SettingsService.Instance.SessionSettings;
if (loadPreviousAssemblies)
{
this.AssemblyList = SettingsService.Instance.AssemblyListManager.LoadList(sessionSettings.ActiveAssemblyList);
}
else
{
SettingsService.Instance.AssemblyListManager.ClearAll();
this.AssemblyList = SettingsService.Instance.AssemblyListManager.CreateList(AssemblyListManager.DefaultListName);
}
this.AssemblyList = SettingsService.Instance.LoadInitialAssemblyList();
HandleCommandLineArguments(App.CommandLineArguments);
var loadPreviousAssemblies = SettingsService.Instance.MiscSettings.LoadPreviousAssemblies;
if (AssemblyList.GetAssemblies().Length == 0
&& AssemblyList.ListName == AssemblyListManager.DefaultListName
&& loadPreviousAssemblies)
@ -340,6 +350,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree @@ -340,6 +350,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
ShowAssemblyList(this.AssemblyList);
var sessionSettings = SettingsService.Instance.SessionSettings;
if (sessionSettings.ActiveAutoLoadedAssembly != null
&& File.Exists(sessionSettings.ActiveAutoLoadedAssembly))
{
@ -742,7 +753,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree @@ -742,7 +753,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
}
if (newState?.ViewedUri != null)
{
MainWindow.Instance.NavigateTo(new(newState.ViewedUri, null), recordHistory: false);
MainWindow.Instance.AssemblyTreeModel.NavigateTo(new(newState.ViewedUri, null), recordHistory: false);
return;
}
@ -768,6 +779,72 @@ namespace ICSharpCode.ILSpy.AssemblyTree @@ -768,6 +779,72 @@ namespace ICSharpCode.ILSpy.AssemblyTree
#endregion
public void NavigateHistory(bool forward)
{
TabPageModel tabPage = DockWorkspace.Instance.ActiveTabPage;
var state = tabPage.GetState();
if (state != null)
history.UpdateCurrent(new NavigationState(tabPage, state));
var newState = forward ? history.GoForward() : history.GoBack();
DockWorkspace.Instance.ActiveTabPage = newState.TabPage;
SelectNodes(newState.TreeNodes, ignoreCompilationRequests: true);
DecompileSelectedNodes(newState.ViewState as DecompilerTextViewState, false);
}
internal void NavigateTo(RequestNavigateEventArgs e, bool recordHistory = true, bool inNewTabPage = false)
{
if (e.Uri.Scheme == "resource")
{
if (inNewTabPage)
{
DockWorkspace.Instance.AddTabPage();
}
if (e.Uri.Host == "aboutpage")
{
RecordHistory();
DockWorkspace.Instance.ActiveTabPage.ShowTextView(AboutPage.Display);
e.Handled = true;
return;
}
AvalonEditTextOutput output = new AvalonEditTextOutput {
Address = e.Uri,
Title = e.Uri.AbsolutePath,
EnableHyperlinks = true
};
using (Stream s = typeof(App).Assembly.GetManifestResourceStream(typeof(App), e.Uri.AbsolutePath))
{
using (StreamReader r = new StreamReader(s))
{
string line;
while ((line = r.ReadLine()) != null)
{
output.Write(line);
output.WriteLine();
}
}
}
RecordHistory();
DockWorkspace.Instance.ShowText(output);
e.Handled = true;
}
void RecordHistory()
{
if (!recordHistory)
return;
TabPageModel tabPage = DockWorkspace.Instance.ActiveTabPage;
var currentState = tabPage.GetState();
if (currentState != null)
history.UpdateCurrent(new NavigationState(tabPage, currentState));
UnselectAll(ignoreCompilationRequests: true);
history.Record(new NavigationState(tabPage, new ViewState { ViewedUri = e.Uri }));
}
}
public void Refresh()
{

2
ILSpy/Commands/CheckForUpdatesCommand.cs

@ -35,7 +35,7 @@ namespace ICSharpCode.ILSpy @@ -35,7 +35,7 @@ namespace ICSharpCode.ILSpy
public override async void Execute(object parameter)
{
await MainWindow.Instance.ShowMessageIfUpdatesAvailableAsync(ILSpySettings.Load(), forceCheck: true);
await MainWindow.Instance.ShowMessageIfUpdatesAvailableAsync(SettingsService.Instance.SpySettings, forceCheck: true);
}
}
}

7
ILSpy/Docking/DockWorkspace.cs

@ -59,6 +59,9 @@ namespace ICSharpCode.ILSpy.Docking @@ -59,6 +59,9 @@ namespace ICSharpCode.ILSpy.Docking
TabPages = new(tabPages);
ToolPanes = new(toolPanes);
// Make sure there is at least one tab open
AddTabPage();
MessageBus<CurrentAssemblyListChangedEventArgs>.Subscribers += (sender, e) => CurrentAssemblyList_Changed(sender, e);
}
@ -146,7 +149,7 @@ namespace ICSharpCode.ILSpy.Docking @@ -146,7 +149,7 @@ namespace ICSharpCode.ILSpy.Docking
return;
}
var state = value.GetState();
var state = value?.GetState();
if (state != null)
{
if (state.DecompiledNodes != null)
@ -155,7 +158,7 @@ namespace ICSharpCode.ILSpy.Docking @@ -155,7 +158,7 @@ namespace ICSharpCode.ILSpy.Docking
}
else
{
MainWindow.Instance.NavigateTo(new(state.ViewedUri, null));
MainWindow.Instance.AssemblyTreeModel.NavigateTo(new(state.ViewedUri, null));
}
}
}

3
ILSpy/ILSpy.csproj

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>

3
ILSpy/Languages/Languages.cs

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System;
using System.Collections.ObjectModel;
using System.Linq;
@ -53,6 +55,7 @@ namespace ICSharpCode.ILSpy @@ -53,6 +55,7 @@ namespace ICSharpCode.ILSpy
}
static ILLanguage ilLanguage;
public static ILLanguage ILLanguage {
get {
if (ilLanguage == null)

113
ILSpy/MainWindow.xaml

@ -1,25 +1,24 @@ @@ -1,25 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<Window x:Class="ICSharpCode.ILSpy.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ICSharpCode.ILSpy"
xmlns:avalondock="https://github.com/Dirkster99/AvalonDock"
xmlns:controls="clr-namespace:ICSharpCode.ILSpy.Controls"
xmlns:docking="clr-namespace:ICSharpCode.ILSpy.Docking"
xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties"
Title="ILSpy"
MinWidth="250"
MinHeight="200"
UseLayoutRounding="True"
TextOptions.TextFormattingMode="Display"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" d:DesignHeight="500" d:DesignWidth="500"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:themes="clr-namespace:ICSharpCode.ILSpy.Themes"
xmlns:toms="urn:TomsToolbox"
xmlns:viewModels="clr-namespace:ICSharpCode.ILSpy.ViewModels"
d:DataContext="{d:DesignInstance local:MainWindowViewModel}">
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ICSharpCode.ILSpy"
xmlns:avalondock="https://github.com/Dirkster99/AvalonDock"
xmlns:controls="clr-namespace:ICSharpCode.ILSpy.Controls"
xmlns:docking="clr-namespace:ICSharpCode.ILSpy.Docking"
xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties"
Title="ILSpy"
MinWidth="250"
MinHeight="200"
UseLayoutRounding="True"
TextOptions.TextFormattingMode="Display"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" d:DesignHeight="500" d:DesignWidth="500"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:themes="clr-namespace:ICSharpCode.ILSpy.Themes"
xmlns:toms="urn:TomsToolbox"
xmlns:viewModels="clr-namespace:ICSharpCode.ILSpy.ViewModels"
d:DataContext="{d:DesignInstance local:MainWindowViewModel}">
<Window.Resources>
<DataTemplate DataType="{x:Type viewModels:TabPageModel}">
@ -77,11 +76,11 @@ @@ -77,11 +76,11 @@
<!-- contents of file menu are added using MEF -->
<MenuItem Header="{x:Static properties:Resources._View}" Tag="_View">
<MenuItem Header="{x:Static properties:Resources.Show_publiconlyTypesMembers}" IsCheckable="True"
IsChecked="{Binding SessionSettings.LanguageSettings.ApiVisPublicOnly}" />
IsChecked="{Binding SessionSettings.LanguageSettings.ApiVisPublicOnly}" />
<MenuItem Header="{x:Static properties:Resources.Show_internalTypesMembers}" IsCheckable="True"
IsChecked="{Binding SessionSettings.LanguageSettings.ApiVisPublicAndInternal}" />
IsChecked="{Binding SessionSettings.LanguageSettings.ApiVisPublicAndInternal}" />
<MenuItem Header="{x:Static properties:Resources.Show_allTypesAndMembers}" IsCheckable="True"
IsChecked="{Binding SessionSettings.LanguageSettings.ApiVisAll}" />
IsChecked="{Binding SessionSettings.LanguageSettings.ApiVisAll}" />
<Separator />
<MenuItem Header="{x:Static properties:Resources.Theme}" ItemsSource="{x:Static themes:ThemeManager.AllThemes}">
<MenuItem.ItemContainerStyle>
@ -103,11 +102,11 @@ @@ -103,11 +102,11 @@
</MenuItem>
<MenuItem Header="{x:Static properties:Resources.UILanguage}">
<MenuItem Header="{x:Static properties:Resources.UILanguage_System}" IsCheckable="True"
IsChecked="{Binding SessionSettings.CurrentCulture, Converter={controls:CultureSelectionConverter}, ConverterParameter={x:Null}}" />
IsChecked="{Binding SessionSettings.CurrentCulture, Converter={controls:CultureSelectionConverter}, ConverterParameter={x:Null}}" />
<MenuItem Header="English" IsCheckable="True"
IsChecked="{Binding SessionSettings.CurrentCulture, Converter={controls:CultureSelectionConverter}, ConverterParameter=en-US}" />
IsChecked="{Binding SessionSettings.CurrentCulture, Converter={controls:CultureSelectionConverter}, ConverterParameter=en-US}" />
<MenuItem Header="中文" IsCheckable="True"
IsChecked="{Binding SessionSettings.CurrentCulture, Converter={controls:CultureSelectionConverter}, ConverterParameter=zh-Hans}" />
IsChecked="{Binding SessionSettings.CurrentCulture, Converter={controls:CultureSelectionConverter}, ConverterParameter=zh-Hans}" />
</MenuItem>
</MenuItem>
<MenuItem Header="{x:Static properties:Resources._Window}" Tag="_Window" />
@ -143,42 +142,42 @@ @@ -143,42 +142,42 @@
<!-- 'Open' toolbar category is inserted here -->
<Separator />
<ComboBox Name="assemblyListComboBox" Width="100" MaxDropDownHeight="Auto"
ItemsSource="{Binding AssemblyListManager.AssemblyLists}"
ToolTip="{x:Static properties:Resources.SelectAssemblyListDropdownTooltip}"
SelectedItem="{Binding SessionSettings.ActiveAssemblyList}" />
ItemsSource="{Binding AssemblyListManager.AssemblyLists}"
ToolTip="{x:Static properties:Resources.SelectAssemblyListDropdownTooltip}"
SelectedItem="{Binding SessionSettings.ActiveAssemblyList}" />
<Button Command="{x:Static local:ILSpyCommands.ManageAssemblyListsCommand}"
ToolTip="{x:Static properties:Resources.ManageAssemblyLists}">
ToolTip="{x:Static properties:Resources.ManageAssemblyLists}">
<Image Width="16" Height="16" Source="{controls:XamlResource Images/AssemblyList}"
Style="{StaticResource DarkModeAwareImageStyle}" />
Style="{StaticResource DarkModeAwareImageStyle}" />
</Button>
<Separator />
<CheckBox IsChecked="{Binding SessionSettings.LanguageSettings.ApiVisPublicOnly}"
ToolTip="{x:Static properties:Resources.ShowPublicOnlyTypesMembers}">
ToolTip="{x:Static properties:Resources.ShowPublicOnlyTypesMembers}">
<Image Width="16" Height="16" Source="{controls:XamlResource Images/ShowPublicOnly}"
Style="{StaticResource DarkModeAwareImageStyle}" />
Style="{StaticResource DarkModeAwareImageStyle}" />
</CheckBox>
<CheckBox IsChecked="{Binding SessionSettings.LanguageSettings.ApiVisPublicAndInternal}"
ToolTip="{x:Static properties:Resources.ShowInternalTypesMembers}">
ToolTip="{x:Static properties:Resources.ShowInternalTypesMembers}">
<Image Width="16" Height="16" Source="{controls:XamlResource Images/ShowPrivateInternal}"
Style="{StaticResource DarkModeAwareImageStyle}" />
Style="{StaticResource DarkModeAwareImageStyle}" />
</CheckBox>
<CheckBox IsChecked="{Binding SessionSettings.LanguageSettings.ApiVisAll}"
ToolTip="{x:Static properties:Resources.ShowAllTypesAndMembers}">
ToolTip="{x:Static properties:Resources.ShowAllTypesAndMembers}">
<Image Width="16" Height="16" Source="{controls:XamlResource Images/ShowAll}"
Style="{StaticResource DarkModeAwareImageStyle}" />
Style="{StaticResource DarkModeAwareImageStyle}" />
</CheckBox>
<Separator />
<ComboBox Name="languageComboBox" DisplayMemberPath="Name" Width="100" MaxDropDownHeight="Auto"
IsEnabled="{Binding Workspace.ActiveTabPage.SupportsLanguageSwitching}"
ItemsSource="{x:Static local:Languages.AllLanguages}"
ToolTip="{x:Static properties:Resources.SelectLanguageDropdownTooltip}"
SelectedItem="{Binding SessionSettings.LanguageSettings.Language}" />
IsEnabled="{Binding Workspace.ActiveTabPage.SupportsLanguageSwitching}"
ItemsSource="{x:Static local:Languages.AllLanguages}"
ToolTip="{x:Static properties:Resources.SelectLanguageDropdownTooltip}"
SelectedItem="{Binding SessionSettings.LanguageSettings.Language}" />
<ComboBox Name="languageVersionComboBox" DisplayMemberPath="DisplayName" Width="120" MaxDropDownHeight="Auto"
ToolTip="{x:Static properties:Resources.SelectVersionDropdownTooltip}"
Visibility="{Binding SelectedItem.HasLanguageVersions, ElementName=languageComboBox, Converter={toms:BooleanToVisibilityConverter}}"
IsEnabled="{Binding Workspace.ActiveTabPage.SupportsLanguageSwitching}"
ItemsSource="{Binding SelectedItem.LanguageVersions, ElementName=languageComboBox, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SessionSettings.LanguageSettings.LanguageVersion, UpdateSourceTrigger=PropertyChanged}" />
ToolTip="{x:Static properties:Resources.SelectVersionDropdownTooltip}"
Visibility="{Binding SelectedItem.HasLanguageVersions, ElementName=languageComboBox, Converter={toms:BooleanToVisibilityConverter}}"
IsEnabled="{Binding Workspace.ActiveTabPage.SupportsLanguageSwitching}"
ItemsSource="{Binding SelectedItem.LanguageVersions, ElementName=languageComboBox, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SessionSettings.LanguageSettings.LanguageVersion, UpdateSourceTrigger=PropertyChanged}" />
</ToolBar>
<!-- Update panel -->
<Border DockPanel.Dock="Top" BorderBrush="Black" BorderThickness="1" Name="updatePanel" Visibility="Collapsed">
@ -186,9 +185,9 @@ @@ -186,9 +185,9 @@
<Button DockPanel.Dock="Right" Click="UpdatePanelCloseButtonClick" MinWidth="0">X</Button>
<StackPanel Orientation="Horizontal">
<TextBlock Name="updatePanelMessage" Margin="4,0" VerticalAlignment="Center"
Text="{x:Static properties:Resources.ILSpyVersionAvailable}" />
Text="{x:Static properties:Resources.ILSpyVersionAvailable}" />
<Button Name="downloadOrCheckUpdateButton" Click="downloadOrCheckUpdateButtonClick"
Content="{x:Static properties:Resources.Download}" />
Content="{x:Static properties:Resources.Download}" />
</StackPanel>
</DockPanel>
</Border>
@ -196,19 +195,19 @@ @@ -196,19 +195,19 @@
<StatusBar x:Name="statusBar" DockPanel.Dock="Bottom" Height="26" Visibility="Collapsed">
<StatusBarItem DockPanel.Dock="Right">
<TextBlock VerticalAlignment="Center"
HorizontalAlignment="Right"
x:Name="statusLabel"
ToolTip="{x:Static properties:Resources.Status}"
Text="{x:Static properties:Resources.StandBy}" />
HorizontalAlignment="Right"
x:Name="statusLabel"
ToolTip="{x:Static properties:Resources.Status}"
Text="{x:Static properties:Resources.StandBy}" />
</StatusBarItem>
</StatusBar>
<avalondock:DockingManager x:Name="dockManager"
DataContext="{Binding Workspace}"
AnchorablesSource="{Binding ToolPanes}"
DocumentsSource="{Binding TabPages}"
ActiveContent="{Binding ActiveTabPage, Mode=TwoWay, Converter={docking:TabPageGuardConverter}}"
AllowMixedOrientation="True">
DataContext="{Binding Workspace}"
AnchorablesSource="{Binding ToolPanes}"
DocumentsSource="{Binding TabPages}"
ActiveContent="{Binding ActiveTabPage, Mode=TwoWay, Converter={docking:TabPageGuardConverter}}"
AllowMixedOrientation="True">
<avalondock:DockingManager.DocumentHeaderTemplate>
<DataTemplate DataType="{x:Type viewModels:PaneModel}">

143
ILSpy/MainWindow.xaml.cs

@ -21,25 +21,21 @@ using System.ComponentModel; @@ -21,25 +21,21 @@ using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Navigation;
using AvalonDock.Layout.Serialization;
using ICSharpCode.ILSpy.AppEnv;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.Search;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.Updates;
using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.ILSpyX.FileLoaders;
using ICSharpCode.ILSpyX.Settings;
using ICSharpCode.ILSpyX.TreeView;
@ -89,6 +85,7 @@ namespace ICSharpCode.ILSpy @@ -89,6 +85,7 @@ namespace ICSharpCode.ILSpy
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo(sessionSettings.CurrentCulture);
}
InitializeComponent();
DockWorkspace.Instance.InitializeLayout(dockManager);
@ -96,8 +93,6 @@ namespace ICSharpCode.ILSpy @@ -96,8 +93,6 @@ namespace ICSharpCode.ILSpy
MenuService.Instance.Init(mainMenu, toolBar, InputBindings);
InitFileLoaders();
this.Loaded += MainWindow_Loaded;
}
void SetWindowBounds(Rect bounds)
@ -132,19 +127,12 @@ namespace ICSharpCode.ILSpy @@ -132,19 +127,12 @@ namespace ICSharpCode.ILSpy
var sessionSettings = SettingsService.Instance.SessionSettings;
// Validate and Set Window Bounds
Rect bounds = Rect.Transform(sessionSettings.WindowBounds, source?.CompositionTarget?.TransformToDevice ?? Matrix.Identity);
var boundsRect = new Rectangle((int)bounds.Left, (int)bounds.Top, (int)bounds.Width, (int)bounds.Height);
bool boundsOK = false;
foreach (var screen in Screen.AllScreens)
{
var intersection = Rectangle.Intersect(boundsRect, screen.WorkingArea);
if (intersection.Width > 10 && intersection.Height > 10)
boundsOK = true;
}
if (boundsOK)
SetWindowBounds(sessionSettings.WindowBounds);
else
SetWindowBounds(SessionSettings.DefaultWindowBounds);
var windowBounds = Rect.Transform(sessionSettings.WindowBounds, source?.CompositionTarget?.TransformToDevice ?? Matrix.Identity);
var boundsRect = new Rectangle((int)windowBounds.Left, (int)windowBounds.Top, (int)windowBounds.Width, (int)windowBounds.Height);
bool areBoundsValid = Screen.AllScreens.Any(screen => Rectangle.Intersect(boundsRect, screen.WorkingArea) is { Width: > 10, Height: > 10 });
SetWindowBounds(areBoundsValid ? sessionSettings.WindowBounds : SessionSettings.DefaultWindowBounds);
this.WindowState = sessionSettings.WindowState;
}
@ -174,28 +162,6 @@ namespace ICSharpCode.ILSpy @@ -174,28 +162,6 @@ namespace ICSharpCode.ILSpy
}
}
internal async Task HandleSingleInstanceCommandLineArguments(string[] args)
{
var cmdArgs = CommandLineArguments.Create(args);
await Dispatcher.InvokeAsync(() => {
if (AssemblyTreeModel.HandleCommandLineArguments(cmdArgs))
{
if (!cmdArgs.NoActivate && WindowState == WindowState.Minimized)
WindowState = WindowState.Normal;
AssemblyTreeModel.HandleCommandLineArgumentsAfterShowList(cmdArgs);
}
});
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
DockWorkspace.Instance.AddTabPage();
AssemblyTreeModel.Initialize();
}
#region Update Check
string updateAvailableDownloadUrl;
@ -229,7 +195,7 @@ namespace ICSharpCode.ILSpy @@ -229,7 +195,7 @@ namespace ICSharpCode.ILSpy
else
{
updatePanel.Visibility = Visibility.Collapsed;
string downloadUrl = await NotifyOfUpdatesStrategy.CheckForUpdatesAsync(ILSpySettings.Load());
string downloadUrl = await NotifyOfUpdatesStrategy.CheckForUpdatesAsync(SettingsService.Instance.SpySettings);
AdjustUpdateUIAfterCheck(downloadUrl, true);
}
}
@ -340,7 +306,7 @@ namespace ICSharpCode.ILSpy @@ -340,7 +306,7 @@ namespace ICSharpCode.ILSpy
if (history.CanNavigateBack)
{
e.Handled = true;
NavigateHistory(false);
AssemblyTreeModel.NavigateHistory(false);
}
}
@ -355,77 +321,11 @@ namespace ICSharpCode.ILSpy @@ -355,77 +321,11 @@ namespace ICSharpCode.ILSpy
if (history.CanNavigateForward)
{
e.Handled = true;
NavigateHistory(true);
AssemblyTreeModel.NavigateHistory(true);
}
}
void NavigateHistory(bool forward)
{
TabPageModel tabPage = DockWorkspace.Instance.ActiveTabPage;
var state = tabPage.GetState();
if (state != null)
history.UpdateCurrent(new NavigationState(tabPage, state));
var newState = forward ? history.GoForward() : history.GoBack();
DockWorkspace.Instance.ActiveTabPage = newState.TabPage;
AssemblyTreeModel.SelectNodes(newState.TreeNodes, ignoreCompilationRequests: true);
AssemblyTreeModel.DecompileSelectedNodes(newState.ViewState as DecompilerTextViewState, false);
}
#endregion
internal void NavigateTo(RequestNavigateEventArgs e, bool recordHistory = true, bool inNewTabPage = false)
{
if (e.Uri.Scheme == "resource")
{
if (inNewTabPage)
{
DockWorkspace.Instance.AddTabPage();
}
if (e.Uri.Host == "aboutpage")
{
RecordHistory();
DockWorkspace.Instance.ActiveTabPage.ShowTextView(AboutPage.Display);
e.Handled = true;
return;
}
AvalonEditTextOutput output = new AvalonEditTextOutput {
Address = e.Uri,
Title = e.Uri.AbsolutePath,
EnableHyperlinks = true
};
using (Stream s = typeof(App).Assembly.GetManifestResourceStream(typeof(App), e.Uri.AbsolutePath))
{
using (StreamReader r = new StreamReader(s))
{
string line;
while ((line = r.ReadLine()) != null)
{
output.Write(line);
output.WriteLine();
}
}
}
RecordHistory();
DockWorkspace.Instance.ShowText(output);
e.Handled = true;
}
void RecordHistory()
{
if (!recordHistory)
return;
TabPageModel tabPage = DockWorkspace.Instance.ActiveTabPage;
var currentState = tabPage.GetState();
if (currentState != null)
history.UpdateCurrent(new NavigationState(tabPage, currentState));
AssemblyTreeModel.UnselectAll(ignoreCompilationRequests: true);
history.Record(new NavigationState(tabPage, new ViewState { ViewedUri = e.Uri }));
}
}
protected override void OnStateChanged(EventArgs e)
{
base.OnStateChanged(e);
@ -447,21 +347,18 @@ namespace ICSharpCode.ILSpy @@ -447,21 +347,18 @@ namespace ICSharpCode.ILSpy
sessionSettings.Save();
}
private string GetAutoLoadedAssemblyNode(SharpTreeNode node)
private static string GetAutoLoadedAssemblyNode(SharpTreeNode node)
{
if (node == null)
return null;
while (!(node is AssemblyTreeNode) && node.Parent != null)
{
node = node.Parent;
}
//this should be an assembly node
var assyNode = node as AssemblyTreeNode;
var loadedAssy = assyNode.LoadedAssembly;
if (!(loadedAssy.IsLoaded && loadedAssy.IsAutoLoaded))
return null;
var assemblyTreeNode = node?
.AncestorsAndSelf()
.OfType<AssemblyTreeNode>()
.FirstOrDefault();
var loadedAssembly = assemblyTreeNode?.LoadedAssembly;
return loadedAssy.FileName;
return loadedAssembly is not { IsLoaded: true, IsAutoLoaded: true }
? null
: loadedAssembly.FileName;
}
}
}

2
ILSpy/Options/MiscSettingsPanel.xaml

@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
<StackPanel Margin="10">
<CheckBox IsChecked="{Binding AllowMultipleInstances}" Content="{x:Static properties:Resources.AllowMultipleInstances}" />
<CheckBox IsChecked="{Binding LoadPreviousAssemblies}" Content="{x:Static properties:Resources.LoadAssembliesThatWereLoadedInTheLastInstance}"/>
<Button Command="{Binding AddRemoveShellIntegrationCommand}" IsEnabled="{Binding EnableShellIntegrationCommand}" Content="{Binding AddRemoveShellIntegrationText}" Margin="3" />
<Button Command="{Binding AddRemoveShellIntegrationCommand}" Content="{Binding AddRemoveShellIntegrationText}" Margin="3" />
</StackPanel>
</GroupBox>
</StackPanel>

30
ILSpy/Options/MiscSettingsPanel.xaml.cs

@ -38,35 +38,25 @@ namespace ICSharpCode.ILSpy.Options @@ -38,35 +38,25 @@ namespace ICSharpCode.ILSpy.Options
public void Load(ILSpySettings settings)
{
this.DataContext = LoadMiscSettings(settings);
}
static MiscSettingsViewModel currentMiscSettings;
public static MiscSettingsViewModel CurrentMiscSettings {
get {
return currentMiscSettings ?? (currentMiscSettings = LoadMiscSettings(ILSpySettings.Load()));
}
}
public static MiscSettingsViewModel LoadMiscSettings(ILSpySettings settings)
{
var s = MiscSettings.Load(settings);
return new MiscSettingsViewModel(s);
this.DataContext = new MiscSettingsViewModel(SettingsService.Instance.MiscSettings);
}
public void Save(XElement root)
{
var s = (MiscSettingsViewModel)this.DataContext;
IMiscSettings.Save(root, s);
if (DataContext is not IMiscSettings miscSettings)
return;
IMiscSettings.Save(root, miscSettings);
currentMiscSettings = null; // invalidate cached settings
SettingsService.Instance.MiscSettings = new() {
AllowMultipleInstances = miscSettings.AllowMultipleInstances,
LoadPreviousAssemblies = miscSettings.LoadPreviousAssemblies
};
}
public void LoadDefaults()
{
currentMiscSettings = new MiscSettingsViewModel(MiscSettings.Load(ILSpySettings.Load()));
this.DataContext = currentMiscSettings;
this.DataContext = new MiscSettingsViewModel(new());
}
}
}

67
ILSpy/Options/MiscSettingsViewModel.cs

@ -24,14 +24,15 @@ using System.Windows; @@ -24,14 +24,15 @@ using System.Windows;
using System.Windows.Input;
using ICSharpCode.ILSpy.AppEnv;
using ICSharpCode.ILSpy.Commands;
using ICSharpCode.ILSpyX.Settings;
using Microsoft.Win32;
using TomsToolbox.Wpf;
namespace ICSharpCode.ILSpy.Options
{
public class MiscSettingsViewModel : IMiscSettings, INotifyPropertyChanged
public class MiscSettingsViewModel : ObservableObject, IMiscSettings
{
bool allowMultipleInstances;
bool loadPreviousAssemblies = true;
@ -40,65 +41,53 @@ namespace ICSharpCode.ILSpy.Options @@ -40,65 +41,53 @@ namespace ICSharpCode.ILSpy.Options
{
AllowMultipleInstances = s.AllowMultipleInstances;
LoadPreviousAssemblies = s.LoadPreviousAssemblies;
if (EnableShellIntegrationCommand)
{
AddRemoveShellIntegrationCommand = new DelegateCommand<object>(AddRemoveShellIntegration);
}
}
/// <summary>
/// Allow multiple instances.
/// </summary>
public bool AllowMultipleInstances {
get { return allowMultipleInstances; }
set {
if (allowMultipleInstances != value)
{
allowMultipleInstances = value;
OnPropertyChanged();
}
}
get => allowMultipleInstances;
set => SetProperty(ref allowMultipleInstances, value);
}
/// <summary>
/// Load assemblies that were loaded in the previous instance
/// </summary>
public bool LoadPreviousAssemblies {
get { return loadPreviousAssemblies; }
set {
if (loadPreviousAssemblies != value)
{
loadPreviousAssemblies = value;
OnPropertyChanged();
}
}
get => loadPreviousAssemblies;
set => SetProperty(ref loadPreviousAssemblies, value);
}
public ICommand AddRemoveShellIntegrationCommand { get; }
public bool EnableShellIntegrationCommand => AppEnvironment.IsWindows;
public ICommand AddRemoveShellIntegrationCommand => new DelegateCommand(() => AppEnvironment.IsWindows, AddRemoveShellIntegration);
const string rootPath = @"Software\Classes\{0}\shell";
const string fullPath = @"Software\Classes\{0}\shell\Open with ILSpy\command";
private void AddRemoveShellIntegration(object obj)
private void AddRemoveShellIntegration()
{
string commandLine = CommandLineTools.ArgumentArrayToCommandLine(Path.ChangeExtension(Assembly.GetEntryAssembly().Location, ".exe")) + " \"%L\"";
string commandLine = CommandLineTools.ArgumentArrayToCommandLine(Path.ChangeExtension(Assembly.GetEntryAssembly()?.Location, ".exe")) + " \"%L\"";
if (RegistryEntriesExist())
{
if (MessageBox.Show(string.Format(Properties.Resources.RemoveShellIntegrationMessage, commandLine), "ILSpy", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
{
Registry.CurrentUser.CreateSubKey(string.Format(rootPath, "dllfile")).DeleteSubKeyTree("Open with ILSpy");
Registry.CurrentUser.CreateSubKey(string.Format(rootPath, "exefile")).DeleteSubKeyTree("Open with ILSpy");
Registry.CurrentUser
.CreateSubKey(string.Format(rootPath, "dllfile"))?
.DeleteSubKeyTree("Open with ILSpy");
Registry.CurrentUser
.CreateSubKey(string.Format(rootPath, "exefile"))?
.DeleteSubKeyTree("Open with ILSpy");
}
}
else
{
if (MessageBox.Show(string.Format(Properties.Resources.AddShellIntegrationMessage, commandLine), "ILSpy", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
{
Registry.CurrentUser.CreateSubKey(string.Format(fullPath, "dllfile"))?
Registry.CurrentUser
.CreateSubKey(string.Format(fullPath, "dllfile"))?
.SetValue("", commandLine);
Registry.CurrentUser.CreateSubKey(string.Format(fullPath, "exefile"))?
Registry.CurrentUser
.CreateSubKey(string.Format(fullPath, "exefile"))?
.SetValue("", commandLine);
}
}
@ -116,21 +105,5 @@ namespace ICSharpCode.ILSpy.Options @@ -116,21 +105,5 @@ namespace ICSharpCode.ILSpy.Options
return RegistryEntriesExist() ? Properties.Resources.RemoveShellIntegration : Properties.Resources.AddShellIntegration;
}
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChanged?.Invoke(this, e);
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}

15
ILSpy/Options/OptionsDialog.xaml.cs

@ -20,9 +20,6 @@ using System; @@ -20,9 +20,6 @@ using System;
using System.ComponentModel.Composition;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Xml.Linq;
using ICSharpCode.ILSpy.Properties;
@ -41,6 +38,7 @@ namespace ICSharpCode.ILSpy.Options @@ -41,6 +38,7 @@ namespace ICSharpCode.ILSpy.Options
}
public string Header { get; }
public UIElement Content { get; }
}
@ -56,7 +54,7 @@ namespace ICSharpCode.ILSpy.Options @@ -56,7 +54,7 @@ namespace ICSharpCode.ILSpy.Options
InitializeComponent();
var ep = App.ExportProvider;
this.optionPages = ep.GetExports<UIElement, IOptionsMetadata>("OptionPages").ToArray();
ILSpySettings settings = ILSpySettings.Load();
ILSpySettings settings = SettingsService.Instance.SpySettings;
foreach (var optionPage in optionPages.OrderBy(p => p.Metadata.Order))
{
var tabItem = new TabItemViewModel(Util.ResourceHelper.GetString(optionPage.Metadata.Title), optionPage.Value);
@ -71,8 +69,8 @@ namespace ICSharpCode.ILSpy.Options @@ -71,8 +69,8 @@ namespace ICSharpCode.ILSpy.Options
void OKButton_Click(object sender, RoutedEventArgs e)
{
ILSpySettings.Update(
delegate (XElement root) {
SettingsService.Instance.SpySettings.Update(
root => {
foreach (var optionPage in optionPages)
{
IOptionPage page = optionPage.Value as IOptionPage;
@ -126,8 +124,9 @@ namespace ICSharpCode.ILSpy.Options @@ -126,8 +124,9 @@ namespace ICSharpCode.ILSpy.Options
{
public override void Execute(object parameter)
{
OptionsDialog dlg = new OptionsDialog();
dlg.Owner = MainWindow.Instance;
OptionsDialog dlg = new() {
Owner = MainWindow.Instance
};
if (dlg.ShowDialog() == true)
{
new RefreshCommand().Execute(parameter);

6
ILSpy/SessionSettings.cs

@ -62,8 +62,8 @@ namespace ICSharpCode.ILSpy @@ -62,8 +62,8 @@ namespace ICSharpCode.ILSpy
this.WindowBounds = FromString((string)doc.Element("WindowBounds"), DefaultWindowBounds);
this.SelectedSearchMode = FromString((string)doc.Element("SelectedSearchMode"), SearchMode.TypeAndMember);
this.Theme = FromString((string)doc.Element(nameof(Theme)), ThemeManager.Current.DefaultTheme);
string currentCulture = (string)doc.Element(nameof(CurrentCulture));
this.CurrentCulture = string.IsNullOrEmpty(currentCulture) ? null : currentCulture;
var culture = (string)doc.Element(nameof(CurrentCulture));
this.CurrentCulture = string.IsNullOrEmpty(culture) ? null : culture;
this.DockLayout = new DockLayoutSettings(doc.Element("DockLayout"));
}
@ -161,7 +161,7 @@ namespace ICSharpCode.ILSpy @@ -161,7 +161,7 @@ namespace ICSharpCode.ILSpy
public void Save()
{
var doc = ToXml();
ILSpySettings.SaveSettings(doc);
SettingsService.Instance.SpySettings.SaveSettings(doc);
}
static Regex regex = new Regex("\\\\x(?<num>[0-9A-f]{4})");

2
ILSpy/Updates/UpdateSettings.cs

@ -75,7 +75,7 @@ namespace ICSharpCode.ILSpy.Updates @@ -75,7 +75,7 @@ namespace ICSharpCode.ILSpy.Updates
updateSettings.Add(new XElement("AutomaticUpdateCheckEnabled", automaticUpdateCheckEnabled));
if (lastSuccessfulUpdateCheck != null)
updateSettings.Add(new XElement("LastSuccessfulUpdateCheck", lastSuccessfulUpdateCheck));
ILSpySettings.SaveSettings(updateSettings);
SettingsService.Instance.SpySettings.SaveSettings(updateSettings);
}
public event PropertyChangedEventHandler PropertyChanged;

18
ILSpy/Util/SettingsService.cs

@ -18,6 +18,7 @@ namespace ICSharpCode.ILSpy.Util @@ -18,6 +18,7 @@ namespace ICSharpCode.ILSpy.Util
SessionSettings = new(SpySettings);
DecompilerSettings = DecompilerSettingsPanel.LoadDecompilerSettings(SpySettings);
DisplaySettings = DisplaySettingsPanel.LoadDisplaySettings(SpySettings, SessionSettings);
MiscSettings = MiscSettings.Load(SpySettings);
AssemblyListManager = new(SpySettings) {
ApplyWinRTProjections = DecompilerSettings.ApplyWindowsRuntimeProjections,
UseDebugSymbols = DecompilerSettings.UseDebugSymbols
@ -32,11 +33,28 @@ namespace ICSharpCode.ILSpy.Util @@ -32,11 +33,28 @@ namespace ICSharpCode.ILSpy.Util
public DisplaySettings DisplaySettings { get; }
public MiscSettings MiscSettings { get; set; }
public AssemblyListManager AssemblyListManager { get; }
public DecompilationOptions CreateDecompilationOptions(TabPageModel tabPage)
{
return new(SessionSettings.LanguageSettings.LanguageVersion, DecompilerSettings, DisplaySettings) { Progress = tabPage.Content as IProgress<DecompilationProgress> };
}
public AssemblyList LoadInitialAssemblyList()
{
var loadPreviousAssemblies = MiscSettings.LoadPreviousAssemblies;
if (loadPreviousAssemblies)
{
return AssemblyListManager.LoadList(SessionSettings.ActiveAssemblyList);
}
else
{
AssemblyListManager.ClearAll();
return AssemblyListManager.CreateList(AssemblyListManager.DefaultListName);
}
}
}
}

Loading…
Cancel
Save