Browse Source

Move command handling from main window to command implementations.

pull/3274/head
tom-englert 8 months ago
parent
commit
0b477f721a
  1. 28
      ILSpy/App.xaml.cs
  2. 2
      ILSpy/AssemblyTree/AssemblyListPane.xaml
  3. 4
      ILSpy/AssemblyTree/AssemblyListPane.xaml.cs
  4. 22
      ILSpy/AssemblyTree/AssemblyTreeModel.cs
  5. 26
      ILSpy/Commands/BrowseBackCommand.cs
  6. 27
      ILSpy/Commands/BrowseForwardCommand.cs
  7. 19
      ILSpy/Commands/CommandWrapper.cs
  8. 26
      ILSpy/Commands/OpenCommand.cs
  9. 19
      ILSpy/Commands/OpenFromGacCommand.cs
  10. 14
      ILSpy/Commands/RefreshCommand.cs
  11. 22
      ILSpy/Commands/SaveCommand.cs
  12. 7
      ILSpy/Commands/SetThemeCommand.cs
  13. 1
      ILSpy/Docking/DockLayoutSettings.cs
  14. 10
      ILSpy/LanguageSettings.cs
  15. 4
      ILSpy/Languages/Languages.cs
  16. 26
      ILSpy/MainWindow.xaml
  17. 115
      ILSpy/MainWindow.xaml.cs
  18. 10
      ILSpy/MainWindowViewModel.cs
  19. 13
      ILSpy/Options/OptionsDialog.xaml.cs
  20. 8
      ILSpy/Search/SearchPane.xaml.cs
  21. 2
      ILSpy/SessionSettings.cs
  22. 2
      ILSpy/TextView/DecompilerTextView.cs
  23. 2
      ILSpy/TreeNodes/AssemblyTreeNode.cs
  24. 48
      ILSpy/Util/NavigationHistoryService.cs
  25. 37
      ILSpy/Util/SettingsService.cs

28
ILSpy/App.xaml.cs

@ -43,6 +43,9 @@ using ICSharpCode.ILSpyX.TreeView; @@ -43,6 +43,9 @@ using ICSharpCode.ILSpyX.TreeView;
using TomsToolbox.Composition;
using TomsToolbox.Wpf.Composition;
using ICSharpCode.ILSpy.Themes;
using System.Globalization;
using System.Threading;
namespace ICSharpCode.ILSpy
{
@ -75,18 +78,20 @@ namespace ICSharpCode.ILSpy @@ -75,18 +78,20 @@ namespace ICSharpCode.ILSpy
SingleInstance.NewInstanceDetected += SingleInstance_NewInstanceDetected;
}
SharpTreeNode.SetImagesProvider(new WpfWindowsTreeNodeImagesProvider());
InitializeComponent();
Resources.RegisterDefaultStyles();
if (!Debugger.IsAttached)
{
AppDomain.CurrentDomain.UnhandledException += ShowErrorBox;
Dispatcher.CurrentDispatcher.UnhandledException += Dispatcher_UnhandledException;
}
TaskScheduler.UnobservedTaskException += DotNet40_UnobservedTaskException;
SharpTreeNode.SetImagesProvider(new WpfWindowsTreeNodeImagesProvider());
Resources.RegisterDefaultStyles();
InitializeMef().GetAwaiter().GetResult();
// Register the export provider so that it can be accessed from WPF/XAML components.
@ -94,6 +99,13 @@ namespace ICSharpCode.ILSpy @@ -94,6 +99,13 @@ namespace ICSharpCode.ILSpy
// Add data templates registered via MEF.
Resources.MergedDictionaries.Add(DataTemplateManager.CreateDynamicDataTemplates(ExportProvider));
var sessionSettings = SettingsService.Instance.SessionSettings;
ThemeManager.Current.Theme = sessionSettings.Theme;
if (!string.IsNullOrEmpty(sessionSettings.CurrentCulture))
{
Thread.CurrentThread.CurrentUICulture = CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(sessionSettings.CurrentCulture);
}
EventManager.RegisterClassHandler(typeof(Window),
Hyperlink.RequestNavigateEvent,
new RequestNavigateEventHandler(Window_RequestNavigate));
@ -109,9 +121,11 @@ namespace ICSharpCode.ILSpy @@ -109,9 +121,11 @@ namespace ICSharpCode.ILSpy
string unknownArguments = string.Join(", ", CommandLineArguments.ArgumentsParser.RemainingArguments);
MessageBox.Show(unknownArguments, "ILSpy Unknown Command Line Arguments Passed");
}
SettingsService.Instance.AssemblyListManager.CreateDefaultAssemblyLists();
}
private static void SingleInstance_NewInstanceDetected(object sender, NewInstanceEventArgs e) => ExportProvider.GetExportedValue<AssemblyListPaneModel>().HandleSingleInstanceCommandLineArguments(e.Args).HandleExceptions();
private static void SingleInstance_NewInstanceDetected(object sender, NewInstanceEventArgs e) => ExportProvider.GetExportedValue<AssemblyTreeModel>().HandleSingleInstanceCommandLineArguments(e.Args).HandleExceptions();
static Assembly ResolvePluginDependencies(AssemblyLoadContext context, AssemblyName assemblyName)
{
@ -203,7 +217,7 @@ namespace ICSharpCode.ILSpy @@ -203,7 +217,7 @@ namespace ICSharpCode.ILSpy
MainWindow = new MainWindow();
MainWindow.Loaded += (sender, args) => {
ExportProvider.GetExportedValue<AssemblyListPaneModel>().Initialize();
ExportProvider.GetExportedValue<AssemblyTreeModel>().Initialize();
};
MainWindow.Show();
}
@ -266,7 +280,7 @@ namespace ICSharpCode.ILSpy @@ -266,7 +280,7 @@ namespace ICSharpCode.ILSpy
void Window_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
ExportProvider.GetExportedValue<AssemblyListPaneModel>().NavigateTo(e);
ExportProvider.GetExportedValue<AssemblyTreeModel>().NavigateTo(e);
}
}
}

2
ILSpy/AssemblyTree/AssemblyListPane.xaml

@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
xmlns:assemblyTree="clr-namespace:ICSharpCode.ILSpy.AssemblyTree"
xmlns:toms="urn:TomsToolbox"
mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance assemblyTree:AssemblyListPaneModel}"
d:DataContext="{d:DesignInstance assemblyTree:AssemblyTreeModel}"
AutomationProperties.Name="Assemblies and Classes"
ShowRoot="False"
AllowDropOrder="True"

4
ILSpy/AssemblyTree/AssemblyListPane.xaml.cs

@ -10,7 +10,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree @@ -10,7 +10,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
/// <summary>
/// Interaction logic for AssemblyListPane.xaml
/// </summary>
[DataTemplate(typeof(AssemblyListPaneModel))]
[DataTemplate(typeof(AssemblyTreeModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class AssemblyListPane
{
@ -27,7 +27,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree @@ -27,7 +27,7 @@ namespace ICSharpCode.ILSpy.AssemblyTree
if (e.Property == DataContextProperty)
{
if (e.NewValue is not AssemblyListPaneModel model)
if (e.NewValue is not AssemblyTreeModel model)
return;
model.SetActiveView(this);

22
ILSpy/AssemblyTree/AssemblyListPaneModel.cs → ILSpy/AssemblyTree/AssemblyTreeModel.cs

@ -45,7 +45,6 @@ using ICSharpCode.Decompiler.Documentation; @@ -45,7 +45,6 @@ using ICSharpCode.Decompiler.Documentation;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using System.Reflection.Metadata;
using ICSharpCode.ILSpyX.Extensions;
using ICSharpCode.ILSpy.AppEnv;
using ICSharpCode.ILSpy.Search;
using ICSharpCode.Decompiler;
@ -60,16 +59,16 @@ namespace ICSharpCode.ILSpy.AssemblyTree @@ -60,16 +59,16 @@ namespace ICSharpCode.ILSpy.AssemblyTree
[ExportToolPane]
[PartCreationPolicy(CreationPolicy.Shared)]
[Export]
public class AssemblyListPaneModel : ToolPaneModel
public class AssemblyTreeModel : ToolPaneModel
{
public const string PaneContentId = "assemblyListPane";
AssemblyListPane activeView;
AssemblyListTreeNode assemblyListTreeNode;
readonly NavigationHistoryService history = NavigationHistoryService.Instance;
readonly NavigationHistory<NavigationState> history = new();
public AssemblyListPaneModel()
public AssemblyTreeModel()
{
Title = Resources.Assemblies;
ContentId = PaneContentId;
@ -795,6 +794,10 @@ namespace ICSharpCode.ILSpy.AssemblyTree @@ -795,6 +794,10 @@ namespace ICSharpCode.ILSpy.AssemblyTree
DecompileSelectedNodes(newState.ViewState as DecompilerTextViewState, false);
}
public bool CanNavigateBack => history.CanNavigateBack;
public bool CanNavigateForward => history.CanNavigateForward;
internal void NavigateTo(RequestNavigateEventArgs e, bool recordHistory = true, bool inNewTabPage = false)
{
if (e.Uri.Scheme == "resource")
@ -914,5 +917,16 @@ namespace ICSharpCode.ILSpy.AssemblyTree @@ -914,5 +917,16 @@ namespace ICSharpCode.ILSpy.AssemblyTree
child.IsExpanded = false;
}
}
public void OpenFiles(string[] fileNames, bool focusNode = true)
{
if (fileNames == null)
throw new ArgumentNullException(nameof(fileNames));
if (focusNode)
UnselectAll();
LoadAssemblies(fileNames, focusNode: focusNode);
}
}
}

26
ILSpy/Commands/BrowseBackCommand.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System.ComponentModel.Composition;
using System.Windows.Input;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Properties;
namespace ICSharpCode.ILSpy
@ -27,9 +28,32 @@ namespace ICSharpCode.ILSpy @@ -27,9 +28,32 @@ namespace ICSharpCode.ILSpy
[PartCreationPolicy(CreationPolicy.Shared)]
sealed class BrowseBackCommand : CommandWrapper
{
public BrowseBackCommand()
readonly AssemblyTreeModel assemblyTreeModel;
[ImportingConstructor]
public BrowseBackCommand(AssemblyTreeModel assemblyTreeModel)
: base(NavigationCommands.BrowseBack)
{
this.assemblyTreeModel = assemblyTreeModel;
}
protected override void OnCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
base.OnCanExecute(sender, e);
e.Handled = true;
e.CanExecute = assemblyTreeModel.CanNavigateBack;
}
protected override void OnExecute(object sender, ExecutedRoutedEventArgs e)
{
base.OnExecute(sender, e);
if (assemblyTreeModel.CanNavigateBack)
{
e.Handled = true;
assemblyTreeModel.NavigateHistory(false);
}
}
}
}

27
ILSpy/Commands/BrowseForwardCommand.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System.ComponentModel.Composition;
using System.Windows.Input;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Properties;
namespace ICSharpCode.ILSpy
@ -27,9 +28,33 @@ namespace ICSharpCode.ILSpy @@ -27,9 +28,33 @@ namespace ICSharpCode.ILSpy
[PartCreationPolicy(CreationPolicy.Shared)]
sealed class BrowseForwardCommand : CommandWrapper
{
public BrowseForwardCommand()
private readonly AssemblyTreeModel assemblyTreeModel;
[ImportingConstructor]
public BrowseForwardCommand(AssemblyTreeModel assemblyTreeModel)
: base(NavigationCommands.BrowseForward)
{
this.assemblyTreeModel = assemblyTreeModel;
}
protected override void OnCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
base.OnCanExecute(sender, e);
e.Handled = true;
e.CanExecute = assemblyTreeModel.CanNavigateForward;
}
protected override void OnExecute(object sender, ExecutedRoutedEventArgs e)
{
base.OnExecute(sender, e);
if (assemblyTreeModel.CanNavigateForward)
{
e.Handled = true;
assemblyTreeModel.NavigateHistory(true);
}
}
}
}

19
ILSpy/Commands/CommandWrapper.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows;
using System.Windows.Input;
namespace ICSharpCode.ILSpy
@ -28,15 +29,16 @@ namespace ICSharpCode.ILSpy @@ -28,15 +29,16 @@ namespace ICSharpCode.ILSpy
public CommandWrapper(ICommand wrappedCommand)
{
this.wrappedCommand = wrappedCommand;
Application.Current.MainWindow?.CommandBindings.Add(new CommandBinding(wrappedCommand, OnExecute, OnCanExecute));
}
public static ICommand Unwrap(ICommand command)
{
CommandWrapper w = command as CommandWrapper;
if (w != null)
if (command is CommandWrapper w)
return w.wrappedCommand;
else
return command;
return command;
}
public event EventHandler CanExecuteChanged {
@ -53,5 +55,14 @@ namespace ICSharpCode.ILSpy @@ -53,5 +55,14 @@ namespace ICSharpCode.ILSpy
{
return wrappedCommand.CanExecute(parameter);
}
protected virtual void OnExecute(object sender, ExecutedRoutedEventArgs e)
{
}
protected virtual void OnCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
}
}

26
ILSpy/Commands/OpenCommand.cs

@ -19,8 +19,11 @@ @@ -19,8 +19,11 @@
using System.ComponentModel.Composition;
using System.Windows.Input;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Properties;
using Microsoft.Win32;
namespace ICSharpCode.ILSpy
{
[ExportToolbarCommand(ToolTip = nameof(Resources.Open), ToolbarIcon = "Images/Open", ToolbarCategory = nameof(Resources.Open), ToolbarOrder = 0)]
@ -28,9 +31,30 @@ namespace ICSharpCode.ILSpy @@ -28,9 +31,30 @@ namespace ICSharpCode.ILSpy
[PartCreationPolicy(CreationPolicy.Shared)]
sealed class OpenCommand : CommandWrapper
{
public OpenCommand()
private readonly AssemblyTreeModel assemblyTreeModel;
[ImportingConstructor]
public OpenCommand(AssemblyTreeModel assemblyTreeModel)
: base(ApplicationCommands.Open)
{
this.assemblyTreeModel = assemblyTreeModel;
}
protected override void OnExecute(object sender, ExecutedRoutedEventArgs e)
{
base.OnExecute(sender, e);
e.Handled = true;
OpenFileDialog dlg = new OpenFileDialog {
Filter = ".NET assemblies|*.dll;*.exe;*.winmd;*.wasm|Nuget Packages (*.nupkg)|*.nupkg|Portable Program Database (*.pdb)|*.pdb|All files|*.*",
Multiselect = true,
RestoreDirectory = true
};
if (dlg.ShowDialog() == true)
{
assemblyTreeModel.OpenFiles(dlg.FileNames);
}
}
}
}

19
ILSpy/Commands/OpenFromGacCommand.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System.ComponentModel.Composition;
using ICSharpCode.ILSpy.AppEnv;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Properties;
namespace ICSharpCode.ILSpy
@ -27,6 +28,14 @@ namespace ICSharpCode.ILSpy @@ -27,6 +28,14 @@ namespace ICSharpCode.ILSpy
[PartCreationPolicy(CreationPolicy.Shared)]
sealed class OpenFromGacCommand : SimpleCommand
{
private readonly AssemblyTreeModel assemblyTreeModel;
[ImportingConstructor]
public OpenFromGacCommand(AssemblyTreeModel assemblyTreeModel)
{
this.assemblyTreeModel = assemblyTreeModel;
}
public override bool CanExecute(object parameter)
{
return AppEnvironment.IsWindows;
@ -34,10 +43,14 @@ namespace ICSharpCode.ILSpy @@ -34,10 +43,14 @@ namespace ICSharpCode.ILSpy
public override void Execute(object parameter)
{
OpenFromGacDialog dlg = new OpenFromGacDialog();
dlg.Owner = MainWindow.Instance;
OpenFromGacDialog dlg = new OpenFromGacDialog {
Owner = MainWindow.Instance
};
if (dlg.ShowDialog() == true)
MainWindow.Instance.OpenFiles(dlg.SelectedFileNames);
{
assemblyTreeModel.OpenFiles(dlg.SelectedFileNames);
}
}
}
}

14
ILSpy/Commands/RefreshCommand.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System.ComponentModel.Composition;
using System.Windows.Input;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Properties;
namespace ICSharpCode.ILSpy
@ -28,9 +29,20 @@ namespace ICSharpCode.ILSpy @@ -28,9 +29,20 @@ namespace ICSharpCode.ILSpy
[PartCreationPolicy(CreationPolicy.Shared)]
sealed class RefreshCommand : CommandWrapper
{
public RefreshCommand()
private readonly AssemblyTreeModel assemblyTreeModel;
[ImportingConstructor]
public RefreshCommand(AssemblyTreeModel assemblyTreeModel)
: base(NavigationCommands.Refresh)
{
this.assemblyTreeModel = assemblyTreeModel;
}
protected override void OnExecute(object sender, ExecutedRoutedEventArgs e)
{
base.OnExecute(sender, e);
assemblyTreeModel.Refresh();
}
}
}

22
ILSpy/Commands/SaveCommand.cs

@ -17,9 +17,12 @@ @@ -17,9 +17,12 @@
// DEALINGS IN THE SOFTWARE.
using System.ComponentModel.Composition;
using System.Linq;
using System.Windows.Input;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TextView;
namespace ICSharpCode.ILSpy
{
@ -27,9 +30,26 @@ namespace ICSharpCode.ILSpy @@ -27,9 +30,26 @@ namespace ICSharpCode.ILSpy
[PartCreationPolicy(CreationPolicy.Shared)]
sealed class SaveCommand : CommandWrapper
{
public SaveCommand()
private AssemblyTreeModel assemblyTreeModel;
[ImportingConstructor]
public SaveCommand(AssemblyTreeModel assemblyTreeModel)
: base(ApplicationCommands.Save)
{
this.assemblyTreeModel = assemblyTreeModel;
}
protected override void OnCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.Handled = true;
e.CanExecute = SaveCodeContextMenuEntry.CanExecute(assemblyTreeModel.SelectedNodes.ToList());
}
protected override void OnExecute(object sender, ExecutedRoutedEventArgs e)
{
base.OnExecute(sender, e);
SaveCodeContextMenuEntry.Execute(assemblyTreeModel.SelectedNodes.ToList());
}
}
}

7
ILSpy/Commands/SetThemeCommand.cs

@ -7,12 +7,7 @@ namespace ICSharpCode.ILSpy.Commands @@ -7,12 +7,7 @@ namespace ICSharpCode.ILSpy.Commands
{
if (parameter is string theme)
{
var snapshot = SettingsService.Instance.CreateSnapshot();
var sessionSettings = snapshot.GetSettings<SessionSettings>();
sessionSettings.Theme = theme;
snapshot.Save();
SettingsService.Instance.SessionSettings.Theme = theme;
}
}
}

1
ILSpy/Docking/DockLayoutSettings.cs

@ -19,7 +19,6 @@ @@ -19,7 +19,6 @@
using System;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using AvalonDock.Layout.Serialization;

10
ILSpy/LanguageSettings.cs

@ -16,11 +16,8 @@ @@ -16,11 +16,8 @@
// 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.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Xml.Linq;
using ICSharpCode.ILSpyX;
@ -32,7 +29,7 @@ namespace ICSharpCode.ILSpy @@ -32,7 +29,7 @@ namespace ICSharpCode.ILSpy
/// <summary>
/// Represents the filters applied to the tree view.
/// </summary>
public class LanguageSettings : ObservableObject
public class LanguageSettings : ObservableObject, IChildSettings
{
/// <summary>
/// This dictionary is necessary to remember language versions across language changes. For example,
@ -41,14 +38,17 @@ namespace ICSharpCode.ILSpy @@ -41,14 +38,17 @@ namespace ICSharpCode.ILSpy
/// </summary>
private readonly Dictionary<Language, LanguageVersion> languageVersionHistory = new Dictionary<Language, LanguageVersion>();
public LanguageSettings(XElement element)
public LanguageSettings(XElement element, ISettingsSection parent)
{
Parent = parent;
this.ShowApiLevel = (ApiVisibility?)(int?)element.Element("ShowAPILevel") ?? ApiVisibility.PublicAndInternal;
this.Language = Languages.GetLanguage((string)element.Element("Language")) ?? Languages.AllLanguages.First();
this.LanguageVersion = Language.LanguageVersions.FirstOrDefault(v => v.Version == (string)element.Element("LanguageVersion"))
?? Language.LanguageVersions.LastOrDefault();
}
public ISettingsSection Parent { get; }
public XElement SaveAsXml()
{
return new XElement(

4
ILSpy/Languages/Languages.cs

@ -33,9 +33,9 @@ namespace ICSharpCode.ILSpy @@ -33,9 +33,9 @@ namespace ICSharpCode.ILSpy
/// </summary>
public static ReadOnlyCollection<Language> AllLanguages { get; } = Initialize(App.ExportProvider);
static ReadOnlyCollection<Language> Initialize(IExportProvider ep)
static ReadOnlyCollection<Language> Initialize(IExportProvider exportProvider)
{
var languages = ep.GetExportedValues<Language>().ToList();
var languages = exportProvider.GetExportedValues<Language>().ToList();
languages.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.Ordinal));
#if DEBUG

26
ILSpy/MainWindow.xaml

@ -35,30 +35,6 @@ @@ -35,30 +35,6 @@
<themes:WindowStyleManagerBehavior />
</b:Interaction.Behaviors>
<Window.CommandBindings>
<CommandBinding
Command="Open"
Executed="OpenCommandExecuted" />
<CommandBinding
Command="Refresh"
Executed="RefreshCommandExecuted" />
<CommandBinding
Command="Save"
CanExecute="SaveCommandCanExecute"
Executed="SaveCommandExecuted" />
<CommandBinding
Command="BrowseBack"
CanExecute="BackCommandCanExecute"
Executed="BackCommandExecuted" />
<CommandBinding
Command="BrowseForward"
CanExecute="ForwardCommandCanExecute"
Executed="ForwardCommandExecuted" />
<CommandBinding
Command="Search"
Executed="SearchCommandExecuted" />
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Key="R" Modifiers="Control" Command="{x:Static local:ILSpyCommands.Analyze}" />
</Window.InputBindings>
@ -184,7 +160,7 @@ @@ -184,7 +160,7 @@
<StackPanel Orientation="Horizontal">
<TextBlock Name="updatePanelMessage" Margin="4,0" VerticalAlignment="Center"
Text="{x:Static properties:Resources.ILSpyVersionAvailable}" />
<Button Name="downloadOrCheckUpdateButton" Click="downloadOrCheckUpdateButtonClick"
<Button Name="downloadOrCheckUpdateButton" Click="DownloadOrCheckUpdateButtonClick"
Content="{x:Static properties:Resources.Download}" />
</StackPanel>
</DockPanel>

115
ILSpy/MainWindow.xaml.cs

@ -20,9 +20,7 @@ using System; @@ -20,9 +20,7 @@ using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
@ -32,17 +30,12 @@ using AvalonDock.Layout.Serialization; @@ -32,17 +30,12 @@ using AvalonDock.Layout.Serialization;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.Search;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.Themes;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.Updates;
using ICSharpCode.ILSpyX.FileLoaders;
using ICSharpCode.ILSpyX.Settings;
using ICSharpCode.ILSpyX.TreeView;
using Microsoft.Win32;
using Screen = System.Windows.Forms.Screen;
namespace ICSharpCode.ILSpy
@ -52,17 +45,17 @@ namespace ICSharpCode.ILSpy @@ -52,17 +45,17 @@ namespace ICSharpCode.ILSpy
/// </summary>
partial class MainWindow : Window
{
readonly NavigationHistoryService history = NavigationHistoryService.Instance;
static MainWindow instance;
private readonly MainWindowViewModel mainWindowViewModel = new();
public static MainWindow Instance {
get { return instance; }
}
public AssemblyListPaneModel AssemblyTreeModel {
public AssemblyTreeModel AssemblyTreeModel {
get {
return App.ExportProvider.GetExportedValue<AssemblyListPaneModel>();
return App.ExportProvider.GetExportedValue<AssemblyTreeModel>();
}
}
@ -70,27 +63,14 @@ namespace ICSharpCode.ILSpy @@ -70,27 +63,14 @@ namespace ICSharpCode.ILSpy
{
instance = this;
var sessionSettings = SettingsService.Instance.SessionSettings;
ThemeManager.Current.Theme = sessionSettings.Theme;
// Make sure Images are initialized on the UI thread.
this.Icon = Images.ILSpyIcon;
this.DataContext = new MainWindowViewModel {
Workspace = DockWorkspace.Instance,
SessionSettings = sessionSettings,
AssemblyListManager = SettingsService.Instance.AssemblyListManager
};
SettingsService.Instance.AssemblyListManager.CreateDefaultAssemblyLists();
if (!string.IsNullOrEmpty(sessionSettings.CurrentCulture))
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo(sessionSettings.CurrentCulture);
}
this.DataContext = mainWindowViewModel;
InitializeComponent();
DockWorkspace.Instance.InitializeLayout(dockManager);
mainWindowViewModel.Workspace.InitializeLayout(dockManager);
MenuService.Instance.Init(mainMenu, toolBar, InputBindings);
@ -165,6 +145,7 @@ namespace ICSharpCode.ILSpy @@ -165,6 +145,7 @@ namespace ICSharpCode.ILSpy
}
#region Update Check
string updateAvailableDownloadUrl;
public async Task ShowMessageIfUpdatesAvailableAsync(ISettingsProvider spySettings, bool forceCheck = false)
@ -188,7 +169,7 @@ namespace ICSharpCode.ILSpy @@ -188,7 +169,7 @@ namespace ICSharpCode.ILSpy
updatePanel.Visibility = Visibility.Collapsed;
}
async void downloadOrCheckUpdateButtonClick(object sender, RoutedEventArgs e)
async void DownloadOrCheckUpdateButtonClick(object sender, RoutedEventArgs e)
{
if (updateAvailableDownloadUrl != null)
{
@ -217,6 +198,7 @@ namespace ICSharpCode.ILSpy @@ -217,6 +198,7 @@ namespace ICSharpCode.ILSpy
downloadOrCheckUpdateButton.Content = Properties.Resources.CheckAgain;
}
}
#endregion
public static void OpenLink(string link)
@ -249,85 +231,6 @@ namespace ICSharpCode.ILSpy @@ -249,85 +231,6 @@ namespace ICSharpCode.ILSpy
}
}
#region Open/Refresh
void OpenCommandExecuted(object sender, ExecutedRoutedEventArgs e)
{
e.Handled = true;
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = ".NET assemblies|*.dll;*.exe;*.winmd;*.wasm|Nuget Packages (*.nupkg)|*.nupkg|Portable Program Database (*.pdb)|*.pdb|All files|*.*";
dlg.Multiselect = true;
dlg.RestoreDirectory = true;
if (dlg.ShowDialog() == true)
{
OpenFiles(dlg.FileNames);
}
}
public void OpenFiles(string[] fileNames, bool focusNode = true)
{
if (fileNames == null)
throw new ArgumentNullException(nameof(fileNames));
if (focusNode)
AssemblyTreeModel.UnselectAll();
AssemblyTreeModel.LoadAssemblies(fileNames, focusNode: focusNode);
}
void RefreshCommandExecuted(object sender, ExecutedRoutedEventArgs e)
{
AssemblyTreeModel.Refresh();
}
void SearchCommandExecuted(object sender, ExecutedRoutedEventArgs e)
{
DockWorkspace.Instance.ShowToolPane(SearchPaneModel.PaneContentId);
}
#endregion
void SaveCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.Handled = true;
e.CanExecute = SaveCodeContextMenuEntry.CanExecute(AssemblyTreeModel.SelectedNodes.ToList());
}
void SaveCommandExecuted(object sender, ExecutedRoutedEventArgs e)
{
SaveCodeContextMenuEntry.Execute(AssemblyTreeModel.SelectedNodes.ToList());
}
#region Back/Forward navigation
void BackCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.Handled = true;
e.CanExecute = history.CanNavigateBack;
}
void BackCommandExecuted(object sender, ExecutedRoutedEventArgs e)
{
if (history.CanNavigateBack)
{
e.Handled = true;
AssemblyTreeModel.NavigateHistory(false);
}
}
void ForwardCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.Handled = true;
e.CanExecute = history.CanNavigateForward;
}
void ForwardCommandExecuted(object sender, ExecutedRoutedEventArgs e)
{
if (history.CanNavigateForward)
{
e.Handled = true;
AssemblyTreeModel.NavigateHistory(true);
}
}
#endregion
protected override void OnStateChanged(EventArgs e)
{
base.OnStateChanged(e);

10
ILSpy/MainWindowViewModel.cs

@ -19,12 +19,14 @@ @@ -19,12 +19,14 @@
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpyX;
using TomsToolbox.Wpf;
namespace ICSharpCode.ILSpy
{
class MainWindowViewModel
class MainWindowViewModel : ObservableObject
{
public DockWorkspace Workspace { get; set; }
public SessionSettings SessionSettings { get; set; }
public AssemblyListManager AssemblyListManager { get; set; }
public DockWorkspace Workspace => DockWorkspace.Instance;
public SessionSettings SessionSettings => SettingsService.Instance.SessionSettings;
public AssemblyListManager AssemblyListManager => SettingsService.Instance.AssemblyListManager;
}
}

13
ILSpy/Options/OptionsDialog.xaml.cs

@ -18,10 +18,9 @@ @@ -18,10 +18,9 @@
using System;
using System.ComponentModel.Composition;
using System.Xml.Linq;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpyX.Settings;
namespace ICSharpCode.ILSpy.Options
{
@ -62,6 +61,14 @@ namespace ICSharpCode.ILSpy.Options @@ -62,6 +61,14 @@ namespace ICSharpCode.ILSpy.Options
[PartCreationPolicy(CreationPolicy.Shared)]
sealed class ShowOptionsCommand : SimpleCommand
{
private readonly AssemblyTreeModel assemblyTreeModel;
[ImportingConstructor]
public ShowOptionsCommand(AssemblyTreeModel assemblyTreeModel)
{
this.assemblyTreeModel = assemblyTreeModel;
}
public override void Execute(object parameter)
{
OptionsDialog dlg = new() {
@ -69,7 +76,7 @@ namespace ICSharpCode.ILSpy.Options @@ -69,7 +76,7 @@ namespace ICSharpCode.ILSpy.Options
};
if (dlg.ShowDialog() == true)
{
new RefreshCommand().Execute(parameter);
assemblyTreeModel.Refresh();
}
}
}

8
ILSpy/Search/SearchPane.xaml.cs

@ -33,6 +33,7 @@ using System.Windows.Media; @@ -33,6 +33,7 @@ using System.Windows.Media;
using System.Windows.Threading;
using ICSharpCode.ILSpy.AppEnv;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpyX.Extensions;
@ -546,5 +547,12 @@ namespace ICSharpCode.ILSpy.Search @@ -546,5 +547,12 @@ namespace ICSharpCode.ILSpy.Search
gestures.Add(new KeyGesture(Key.F, ModifierKeys.Control | ModifierKeys.Shift));
gestures.Add(new KeyGesture(Key.E, ModifierKeys.Control));
}
protected override void OnExecute(object sender, ExecutedRoutedEventArgs e)
{
base.OnExecute(sender, e);
DockWorkspace.Instance.ShowToolPane(SearchPaneModel.PaneContentId);
}
}
}

2
ILSpy/SessionSettings.cs

@ -45,7 +45,7 @@ namespace ICSharpCode.ILSpy @@ -45,7 +45,7 @@ namespace ICSharpCode.ILSpy
{
XElement filterSettings = section.Element("FilterSettings") ?? new XElement("FilterSettings");
LanguageSettings = new(filterSettings);
LanguageSettings = new(filterSettings, this);
LanguageSettings.PropertyChanged += (sender, e) => PropertyChanged?.Invoke(sender, e);
ActiveAssemblyList = (string)section.Element("ActiveAssemblyList");

2
ILSpy/TextView/DecompilerTextView.cs

@ -474,7 +474,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -474,7 +474,7 @@ namespace ICSharpCode.ILSpy.TextView
IEntity? ResolveReference(string idString)
{
return AssemblyListPaneModel.FindEntityInRelevantAssemblies(idString, MainWindow.Instance.AssemblyTreeModel.AssemblyList.GetAssemblies());
return AssemblyTreeModel.FindEntityInRelevantAssemblies(idString, MainWindow.Instance.AssemblyTreeModel.AssemblyList.GetAssemblies());
}
}

2
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -631,7 +631,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -631,7 +631,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
{
foreach (var node in context.SelectedTreeNodes)
{
paths.Add(AssemblyListPaneModel.GetPathForNode(node));
paths.Add(AssemblyTreeModel.GetPathForNode(node));
var la = ((AssemblyTreeNode)node).LoadedAssembly;
la.AssemblyList.ReloadAssembly(la.FileName);
}

48
ILSpy/Util/NavigationHistoryService.cs

@ -1,48 +0,0 @@ @@ -1,48 +0,0 @@
using System;
namespace ICSharpCode.ILSpy.Util
{
public class NavigationHistoryService
{
readonly NavigationHistory<NavigationState> history = new();
public static NavigationHistoryService Instance { get; } = new();
public bool CanNavigateBack => history.CanNavigateBack;
public bool CanNavigateForward => history.CanNavigateForward;
private NavigationHistoryService()
{
}
public void UpdateCurrent(NavigationState navigationState)
{
history.UpdateCurrent(navigationState);
}
public void Record(NavigationState navigationState)
{
history.Record(navigationState);
}
public NavigationState GoForward()
{
return history.GoForward();
}
public NavigationState GoBack()
{
return history.GoBack();
}
public void Clear()
{
history.Clear();
}
public void RemoveAll(Predicate<NavigationState> predicate)
{
history.RemoveAll(predicate);
}
}
}

37
ILSpy/Util/SettingsService.cs

@ -15,6 +15,11 @@ using DecompilerSettings = ICSharpCode.ILSpy.Options.DecompilerSettings; @@ -15,6 +15,11 @@ using DecompilerSettings = ICSharpCode.ILSpy.Options.DecompilerSettings;
namespace ICSharpCode.ILSpy.Util
{
public interface IChildSettings
{
ISettingsSection Parent { get; }
}
public interface ISettingsSection : INotifyPropertyChanged
{
XName SectionName { get; }
@ -49,6 +54,19 @@ namespace ICSharpCode.ILSpy.Util @@ -49,6 +54,19 @@ namespace ICSharpCode.ILSpy.Util
});
}
protected void SaveSection(ISettingsSection section, XElement root)
{
var element = SpySettings[section.SectionName];
section.SaveToSection(element);
var existingElement = root.Element(section.SectionName);
if (existingElement != null)
existingElement.ReplaceWith(element);
else
root.Add(element);
}
protected virtual void Section_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
}
@ -68,15 +86,7 @@ namespace ICSharpCode.ILSpy.Util @@ -68,15 +86,7 @@ namespace ICSharpCode.ILSpy.Util
SpySettings.Update(root => {
foreach (var section in sections.Values)
{
var element = SpySettings[section.SectionName];
section.SaveToSection(element);
var existingElement = root.Element(section.SectionName);
if (existingElement != null)
existingElement.ReplaceWith(element);
else
root.Add(element);
SaveSection(section, root);
}
});
@ -160,7 +170,14 @@ namespace ICSharpCode.ILSpy.Util @@ -160,7 +170,14 @@ namespace ICSharpCode.ILSpy.Util
if (!reloading)
{
throw new InvalidOperationException("Settings are read only, use a snapshot to modify.");
var section = (sender as IChildSettings)?.Parent ?? sender as ISettingsSection;
if (section != null)
{
SpySettings.Update(root => {
SaveSection(section, root);
});
};
}
if (sender is DecompilerSettings decompilerSettings && assemblyListManager != null)

Loading…
Cancel
Save