Skip to content

Commit

Permalink
Decouple services to reduce circular dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
tom-englert committed Oct 27, 2024
1 parent ca8b46a commit 291f9f5
Show file tree
Hide file tree
Showing 18 changed files with 117 additions and 125 deletions.
1 change: 1 addition & 0 deletions ICSharpCode.ILSpyX/Analyzers/IAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public interface IAnalyzer
public interface IAnalyzerMetadata
{
string Header { get; }

int Order { get; }
}
}
6 changes: 3 additions & 3 deletions ILSpy/AboutPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,14 @@ private void Display(DecompilerTextView textView)
HorizontalAlignment = HorizontalAlignment.Center,
Orientation = Orientation.Horizontal
};
if (NotifyOfUpdatesStrategy.LatestAvailableVersion == null)
if (UpdateService.LatestAvailableVersion == null)
{
AddUpdateCheckButton(stackPanel, textView);
}
else
{
// we already retrieved the latest version sometime earlier
ShowAvailableVersion(NotifyOfUpdatesStrategy.LatestAvailableVersion, stackPanel);
ShowAvailableVersion(UpdateService.LatestAvailableVersion, stackPanel);
}
CheckBox checkBox = new() {
Margin = new Thickness(4),
Expand Down Expand Up @@ -171,7 +171,7 @@ static void AddUpdateCheckButton(StackPanel stackPanel, DecompilerTextView textV

try
{
AvailableVersionInfo vInfo = await NotifyOfUpdatesStrategy.GetLatestVersionAsync();
AvailableVersionInfo vInfo = await UpdateService.GetLatestVersionAsync();
stackPanel.Children.Clear();
ShowAvailableVersion(vInfo, stackPanel);
}
Expand Down
4 changes: 1 addition & 3 deletions ILSpy/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
using System.Runtime.Loader;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Navigation;
using System.Windows.Threading;

using ICSharpCode.ILSpy.AppEnv;
Expand Down Expand Up @@ -135,7 +133,7 @@ public App()

public new MainWindow MainWindow {
get => (MainWindow)base.MainWindow;
set => base.MainWindow = value;
private set => base.MainWindow = value;
}

private static void SingleInstance_NewInstanceDetected(object sender, NewInstanceEventArgs e) => ExportProvider.GetExportedValue<AssemblyTreeModel>().HandleSingleInstanceCommandLineArguments(e.Args).HandleExceptions();
Expand Down
2 changes: 1 addition & 1 deletion ILSpy/AssemblyTree/AssemblyTreeModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ private async Task NavigateOnLaunch(string? navigateTo, string[]? activeTreeView
SelectNode(node);

// only if not showing the about page, perform the update check:
await App.Current.MainWindow.ShowMessageIfUpdatesAvailableAsync(updateSettings);
MessageBus.Send(this, new CheckIfUpdateAvailableEventArgs());
}
else
{
Expand Down
3 changes: 1 addition & 2 deletions ILSpy/Commands/CheckForUpdatesCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
using System.Composition;

using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.Updates;

namespace ICSharpCode.ILSpy
{
Expand All @@ -30,7 +29,7 @@ sealed class CheckForUpdatesCommand(SettingsService settingsService) : SimpleCom
{
public override async void Execute(object parameter)

Check warning on line 30 in ILSpy/Commands/CheckForUpdatesCommand.cs

View workflow job for this annotation

GitHub Actions / Build (Debug)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 30 in ILSpy/Commands/CheckForUpdatesCommand.cs

View workflow job for this annotation

GitHub Actions / Build (Debug)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 30 in ILSpy/Commands/CheckForUpdatesCommand.cs

View workflow job for this annotation

GitHub Actions / Build (Release)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 30 in ILSpy/Commands/CheckForUpdatesCommand.cs

View workflow job for this annotation

GitHub Actions / Build (Release)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
await App.Current.MainWindow.ShowMessageIfUpdatesAvailableAsync(settingsService.GetSettings<UpdateSettings>(), forceCheck: true);
MessageBus.Send(this, new CheckIfUpdateAvailableEventArgs(notify: true));
}
}
}
4 changes: 2 additions & 2 deletions ILSpy/Commands/ExitCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ namespace ICSharpCode.ILSpy
{
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.E_xit), MenuOrder = 99999, MenuCategory = nameof(Resources.Exit))]
[Shared]
sealed class ExitCommand : SimpleCommand
sealed class ExitCommand(MainWindow mainWindow) : SimpleCommand
{
public override void Execute(object parameter)
{
App.Current.MainWindow.Close();
mainWindow.Close();
}
}
}
16 changes: 13 additions & 3 deletions ILSpy/Commands/ManageAssemblyListsCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,30 @@


using System.Composition;
using System.Windows;
using System.Windows.Data;

using ICSharpCode.ILSpy.Properties;

namespace ICSharpCode.ILSpy
{
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.ManageAssembly_Lists), MenuIcon = "Images/AssemblyList", MenuCategory = nameof(Resources.Open), MenuOrder = 1.7)]
[Shared]
sealed class ManageAssemblyListsCommand(SettingsService settingsService) : SimpleCommand
sealed class ManageAssemblyListsCommand(SettingsService settingsService) : SimpleCommand, IProvideParameterBinding
{
public override void Execute(object parameter)
{
ManageAssemblyListsDialog dlg = new ManageAssemblyListsDialog(settingsService);
dlg.Owner = App.Current.MainWindow;
ManageAssemblyListsDialog dlg = new(settingsService) {
Owner = parameter as Window
};

dlg.ShowDialog();
}

public Binding ParameterBinding => new() {
RelativeSource = new(RelativeSourceMode.FindAncestor) {
AncestorType = typeof(Window)
}
};
}
}
13 changes: 3 additions & 10 deletions ILSpy/Commands/OpenFromGacCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,17 @@ namespace ICSharpCode.ILSpy
{
[ExportMainMenuCommand(ParentMenuID = nameof(Resources._File), Header = nameof(Resources.OpenFrom_GAC), MenuIcon = "Images/AssemblyListGAC", MenuCategory = nameof(Resources.Open), MenuOrder = 1)]
[Shared]
sealed class OpenFromGacCommand : SimpleCommand
sealed class OpenFromGacCommand(AssemblyTreeModel assemblyTreeModel, MainWindow mainWindow) : SimpleCommand
{
private readonly AssemblyTreeModel assemblyTreeModel;

public OpenFromGacCommand(AssemblyTreeModel assemblyTreeModel)
{
this.assemblyTreeModel = assemblyTreeModel;
}

public override bool CanExecute(object parameter)
{
return AppEnvironment.IsWindows;
}

public override void Execute(object parameter)
{
OpenFromGacDialog dlg = new OpenFromGacDialog {
Owner = App.Current.MainWindow
OpenFromGacDialog dlg = new() {
Owner = mainWindow
};

if (dlg.ShowDialog() == true)
Expand Down
36 changes: 3 additions & 33 deletions ILSpy/Commands/SimpleCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// DEALINGS IN THE SOFTWARE.

using System;
using System.ComponentModel;
using System.Windows.Data;
using System.Windows.Input;

namespace ICSharpCode.ILSpy
Expand All @@ -37,38 +37,8 @@ public virtual bool CanExecute(object parameter)
}
}

public abstract class ToggleableCommand : ICommand, INotifyPropertyChanged
public interface IProvideParameterBinding
{
private bool isChecked;

public event EventHandler CanExecuteChanged {
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}

public event PropertyChangedEventHandler PropertyChanged;

void ICommand.Execute(object parameter)
{
IsChecked = Execute(parameter);
}

public bool IsChecked {
get => isChecked;
set {
if (isChecked != value)
{
isChecked = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsChecked)));
}
}
}

public abstract bool Execute(object parameter);

public virtual bool CanExecute(object parameter)
{
return true;
}
Binding ParameterBinding { get; }
}
}
18 changes: 8 additions & 10 deletions ILSpy/Docking/DockWorkspace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@

using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.ILSpy.Analyzers;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpy.Search;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.ViewModels;
Expand All @@ -50,17 +49,17 @@ public class DockWorkspace : ObservableObject, ILayoutUpdateStrategy
{
private readonly IExportProvider exportProvider;

private SessionSettings SessionSettings { get; }

private readonly ObservableCollection<TabPageModel> tabPages = [];

readonly SessionSettings sessionSettings;

private DockingManager DockingManager => exportProvider.GetExportedValue<DockingManager>();

public DockWorkspace(SettingsService settingsService, IExportProvider exportProvider)
{
this.exportProvider = exportProvider;

SessionSettings = settingsService.SessionSettings;
sessionSettings = settingsService.SessionSettings;

this.tabPages.CollectionChanged += TabPages_CollectionChanged;
TabPages = new(tabPages);
Expand All @@ -70,10 +69,9 @@ public DockWorkspace(SettingsService settingsService, IExportProvider exportProv

private void CurrentAssemblyList_Changed(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.OldItems == null)
{
if (e.OldItems is not { } oldItems)
return;
}

foreach (var tab in tabPages.ToArray())
{
var state = tab.GetState();
Expand All @@ -84,7 +82,7 @@ private void CurrentAssemblyList_Changed(object sender, NotifyCollectionChangedE
bool found = decompiledNodes
.Select(node => node.Ancestors().OfType<TreeNodes.AssemblyTreeNode>().LastOrDefault())
.ExceptNullItems()
.Any(assemblyNode => !e.OldItems.Contains(assemblyNode.LoadedAssembly));
.Any(assemblyNode => !oldItems.Contains(assemblyNode.LoadedAssembly));

if (!found)
{
Expand Down Expand Up @@ -190,7 +188,7 @@ public void InitializeLayout()
serializer.LayoutSerializationCallback += LayoutSerializationCallback;
try
{
SessionSettings.DockLayout.Deserialize(serializer);
sessionSettings.DockLayout.Deserialize(serializer);
}
finally
{
Expand Down Expand Up @@ -247,7 +245,7 @@ internal void ResetLayout()
pane.IsVisible = false;
}
CloseAllTabs();
SessionSettings.DockLayout.Reset();
sessionSettings.DockLayout.Reset();
InitializeLayout();

App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, () => MessageBus.Send(this, new ResetLayoutEventArgs()));
Expand Down
14 changes: 9 additions & 5 deletions ILSpy/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@
<DockPanel>
<!-- Main menu -->
<Menu DockPanel.Dock="Top" Name="mainMenu" Height="23" KeyboardNavigation.TabNavigation="None">
<MenuItem Header="{x:Static properties:Resources._File}" Tag="_File" />
<!-- contents of file menu are added using MEF -->
<MenuItem Header="{x:Static properties:Resources._File}" Tag="_File">
<!-- content of file menu is added using MEF -->
</MenuItem>
<MenuItem Header="{x:Static properties:Resources._View}" Tag="_View">
<MenuItem Header="{x:Static properties:Resources.Show_publiconlyTypesMembers}" IsCheckable="True"
IsChecked="{Binding SessionSettings.LanguageSettings.ApiVisPublicOnly}" />
Expand All @@ -63,7 +64,7 @@
<MenuItem Header="{x:Static properties:Resources.Theme}" ItemsSource="{x:Static themes:ThemeManager.AllThemes}">
<MenuItem.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource {x:Type MenuItem}}">
<Setter Property="Command" Value="{composition:Import {x:Type commands:SetThemeCommand}}" />
<Setter Property="Command" Value="{composition:Import commands:SetThemeCommand}" />
<Setter Property="CommandParameter" Value="{Binding}" />
<Setter Property="IsCheckable" Value="True" />
<!-- Required by AvalonDock's MenuItem style to show the checkmark -->
Expand All @@ -87,7 +88,9 @@
IsChecked="{Binding SessionSettings.CurrentCulture, Converter={controls:CultureSelectionConverter}, ConverterParameter=zh-Hans}" />
</MenuItem>
</MenuItem>
<MenuItem Header="{x:Static properties:Resources._Window}" Tag="_Window" />
<MenuItem Header="{x:Static properties:Resources._Window}" Tag="_Window" >
<!-- content of window menu is added using MEF -->
</MenuItem>
</Menu>
<!-- ToolBar -->
<ToolBar
Expand Down Expand Up @@ -126,7 +129,8 @@
ToolTip="{x:Static properties:Resources.SelectAssemblyListDropdownTooltip}"
SelectedItem="{Binding SessionSettings.ActiveAssemblyList}" />
</Grid>
<Button Command="{composition:Import {x:Type local:ManageAssemblyListsCommand}}"
<Button Command="{composition:Import local:ManageAssemblyListsCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
ToolTip="{x:Static properties:Resources.ManageAssemblyLists}">
<Image Width="16" Height="16" Source="{controls:XamlResource Images/AssemblyList}"
Style="{StaticResource DarkModeAwareImageStyle}" />
Expand Down
24 changes: 11 additions & 13 deletions ILSpy/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Composition;
using System.Diagnostics;
Expand All @@ -30,7 +29,6 @@
using System.Windows.Threading;

using ICSharpCode.ILSpy.Updates;
using ICSharpCode.ILSpyX.FileLoaders;

using Screen = System.Windows.Forms.Screen;

Expand All @@ -55,6 +53,8 @@ public MainWindow(MainWindowViewModel mainWindowViewModel, MenuService menuServi

this.DataContext = mainWindowViewModel;

MessageBus<CheckIfUpdateAvailableEventArgs>.Subscribers += (_, e) => CheckIfUpdatesAvailableAsync(e.Notify).IgnoreExceptions();

InitializeComponent();

Dispatcher.BeginInvoke(DispatcherPriority.Background, () => {
Expand Down Expand Up @@ -122,20 +122,20 @@ protected override void OnKeyDown(KeyEventArgs e)

string updateAvailableDownloadUrl;

public async Task ShowMessageIfUpdatesAvailableAsync(UpdateSettings settings, bool forceCheck = false)
private async Task CheckIfUpdatesAvailableAsync(bool notify = false)
{
var settings = settingsService.GetSettings<UpdateSettings>();
string downloadUrl;
if (forceCheck)
if (notify)
{
downloadUrl = await NotifyOfUpdatesStrategy.CheckForUpdatesAsync(settings);
downloadUrl = await UpdateService.CheckForUpdatesAsync(settings);
}
else
{
downloadUrl = await NotifyOfUpdatesStrategy.CheckForUpdatesIfEnabledAsync(settings);
downloadUrl = await UpdateService.CheckForUpdatesIfEnabledAsync(settings);
}

// The Update Panel is only available for NotifyOfUpdatesStrategy, AutoUpdate will have differing UI requirements
AdjustUpdateUIAfterCheck(downloadUrl, forceCheck);
AdjustUpdateUIAfterCheck(downloadUrl, notify);
}

void UpdatePanelCloseButtonClick(object sender, RoutedEventArgs e)
Expand All @@ -152,15 +152,15 @@ async void DownloadOrCheckUpdateButtonClick(object sender, RoutedEventArgs e)
else
{
updatePanel.Visibility = Visibility.Collapsed;
string downloadUrl = await NotifyOfUpdatesStrategy.CheckForUpdatesAsync(settingsService.GetSettings<UpdateSettings>());
string downloadUrl = await UpdateService.CheckForUpdatesAsync(settingsService.GetSettings<UpdateSettings>());
AdjustUpdateUIAfterCheck(downloadUrl, true);
}
}

void AdjustUpdateUIAfterCheck(string downloadUrl, bool displayMessage)
void AdjustUpdateUIAfterCheck(string downloadUrl, bool notify)
{
updateAvailableDownloadUrl = downloadUrl;
updatePanel.Visibility = displayMessage ? Visibility.Visible : Visibility.Collapsed;
updatePanel.Visibility = notify ? Visibility.Visible : Visibility.Collapsed;
if (downloadUrl != null)
{
updatePanelMessage.Text = Properties.Resources.ILSpyVersionAvailable;
Expand All @@ -180,11 +180,9 @@ public static void OpenLink(string link)
try
{
Process.Start(new ProcessStartInfo { FileName = link, UseShellExecute = true });
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
}
catch (Exception)
{
#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body
// Process.Start can throw several errors (not all of them documented),
// just ignore all of them.
}
Expand Down
Loading

0 comments on commit 291f9f5

Please sign in to comment.