Browse Source

Introduce message bus to start decoupling components

pull/3257/head
tom-englert 11 months ago
parent
commit
cc7de5fe60
  1. 45
      .editorconfig
  2. 2
      ICSharpCode.ILSpyX/TreeView/SharpTreeNode.cs
  3. 37
      ILSpy/Analyzers/AnalyzeCommand.cs
  4. 21
      ILSpy/Analyzers/AnalyzerTreeView.cs
  5. 53
      ILSpy/Docking/DockWorkspace.cs
  6. 18
      ILSpy/Docking/TabPageGuardConverter.cs
  7. 9
      ILSpy/MainWindow.xaml
  8. 44
      ILSpy/MainWindow.xaml.cs
  9. 3
      ILSpy/Search/SearchPane.cs
  10. 55
      ILSpy/Util/MessageBus.cs
  11. 16
      ILSpy/Views/DebugSteps.xaml.cs

45
.editorconfig

@ -120,6 +120,51 @@ csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false csharp_space_between_square_brackets = false
# Naming rules
dotnet_naming_rule.constants_rule.severity = warning
dotnet_naming_rule.constants_rule.style = upper_camel_case_style
dotnet_naming_rule.constants_rule.symbols = constants_symbols
dotnet_naming_rule.private_constants_rule.severity = warning
dotnet_naming_rule.private_constants_rule.style = upper_camel_case_style
dotnet_naming_rule.private_constants_rule.symbols = private_constants_symbols
dotnet_naming_rule.private_instance_fields_rule.severity = warning
dotnet_naming_rule.private_instance_fields_rule.style = lower_camel_case_style
dotnet_naming_rule.private_instance_fields_rule.symbols = private_instance_fields_symbols
dotnet_naming_rule.private_static_fields_rule.severity = warning
dotnet_naming_rule.private_static_fields_rule.style = lower_camel_case_style
dotnet_naming_rule.private_static_fields_rule.symbols = private_static_fields_symbols
dotnet_naming_rule.private_static_readonly_rule.severity = warning
dotnet_naming_rule.private_static_readonly_rule.style = upper_camel_case_style
dotnet_naming_rule.private_static_readonly_rule.symbols = private_static_readonly_symbols
dotnet_naming_rule.public_static_fields_rule.severity = warning
dotnet_naming_rule.public_static_fields_rule.style = lower_camel_case_style
dotnet_naming_rule.public_static_fields_rule.symbols = public_static_fields_symbols
dotnet_naming_rule.static_readonly_rule.severity = warning
dotnet_naming_rule.static_readonly_rule.style = upper_camel_case_style
dotnet_naming_rule.static_readonly_rule.symbols = static_readonly_symbols
dotnet_naming_style.lower_camel_case_style.capitalization = camel_case
dotnet_naming_style.upper_camel_case_style.capitalization = pascal_case
dotnet_naming_symbols.constants_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
dotnet_naming_symbols.constants_symbols.applicable_kinds = field
dotnet_naming_symbols.constants_symbols.required_modifiers = const
dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private
dotnet_naming_symbols.private_constants_symbols.applicable_kinds = field
dotnet_naming_symbols.private_constants_symbols.required_modifiers = const
dotnet_naming_symbols.private_instance_fields_symbols.applicable_accessibilities = private
dotnet_naming_symbols.private_instance_fields_symbols.applicable_kinds = field
dotnet_naming_symbols.private_static_fields_symbols.applicable_accessibilities = private
dotnet_naming_symbols.private_static_fields_symbols.applicable_kinds = field
dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static
dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private
dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field
dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = readonly,static
dotnet_naming_symbols.public_static_fields_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
dotnet_naming_symbols.public_static_fields_symbols.applicable_kinds = field
dotnet_naming_symbols.public_static_fields_symbols.required_modifiers = static
dotnet_naming_symbols.static_readonly_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
dotnet_naming_symbols.static_readonly_symbols.applicable_kinds = field
dotnet_naming_symbols.static_readonly_symbols.required_modifiers = readonly,static
# Errors and warnings # Errors and warnings
# MEF006: No importing constructor # MEF006: No importing constructor

2
ICSharpCode.ILSpyX/TreeView/SharpTreeNode.cs

@ -182,7 +182,7 @@ namespace ICSharpCode.ILSpyX.TreeView
#endregion #endregion
#region OnChildrenChanged #region OnChildrenChanged
internal protected virtual void OnChildrenChanged(NotifyCollectionChangedEventArgs e) protected internal virtual void OnChildrenChanged(NotifyCollectionChangedEventArgs e)
{ {
if (e.OldItems != null) if (e.OldItems != null)
{ {

37
ILSpy/Analyzers/AnalyzeCommand.cs

@ -18,27 +18,18 @@
using System.ComponentModel.Composition; using System.ComponentModel.Composition;
using System.Linq; using System.Linq;
using System.Windows;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
using TomsToolbox.Composition;
namespace ICSharpCode.ILSpy.Analyzers namespace ICSharpCode.ILSpy.Analyzers
{ {
[ExportContextMenuEntry(Header = nameof(Resources.Analyze), Icon = "Images/Search", Category = nameof(Resources.Analyze), InputGestureText = "Ctrl+R", Order = 100)] [ExportContextMenuEntry(Header = nameof(Resources.Analyze), Icon = "Images/Search", Category = nameof(Resources.Analyze), InputGestureText = "Ctrl+R", Order = 100)]
[PartCreationPolicy(CreationPolicy.Shared)] [PartCreationPolicy(CreationPolicy.Shared)]
internal sealed class AnalyzeCommand : SimpleCommand, IContextMenuEntry internal sealed class AnalyzeCommand : SimpleCommand, IContextMenuEntry
{ {
private static readonly IExport<AnalyzerTreeView> analyzerTreeViewExport = App.ExportProvider.GetExports<AnalyzerTreeView>().Single(); private static readonly AnalyzerTreeView AnalyzerTreeView = App.ExportProvider.GetExportedValue<AnalyzerTreeView>();
private static AnalyzerTreeView AnalyzerTreeView {
get {
return Application.Current?.MainWindow?.IsLoaded != true ? null : analyzerTreeViewExport.Value;
}
}
public bool IsVisible(TextViewContext context) public bool IsVisible(TextViewContext context)
{ {
@ -60,17 +51,13 @@ namespace ICSharpCode.ILSpy.Analyzers
.All(node => IsValidReference(node.Member)); .All(node => IsValidReference(node.Member));
} }
bool IsValidReference(object reference) static bool IsValidReference(object reference)
{ {
return reference is IEntity && !(reference is IField f && f.IsConst); return reference is IEntity and not IField { IsConst: true };
} }
public void Execute(TextViewContext context) public void Execute(TextViewContext context)
{ {
if (AnalyzerTreeView is null)
{
return;
}
if (context.SelectedTreeNodes != null) if (context.SelectedTreeNodes != null)
{ {
foreach (var node in context.SelectedTreeNodes.OfType<IMemberTreeNode>().ToArray()) foreach (var node in context.SelectedTreeNodes.OfType<IMemberTreeNode>().ToArray())
@ -86,25 +73,13 @@ namespace ICSharpCode.ILSpy.Analyzers
public override bool CanExecute(object parameter) public override bool CanExecute(object parameter)
{ {
if (AnalyzerTreeView is null) return AnalyzerTreeView.IsKeyboardFocusWithin
{ ? AnalyzerTreeView.SelectedItems.OfType<object>().All(n => n is IMemberTreeNode)
return false; : MainWindow.Instance.SelectedNodes.All(n => n is IMemberTreeNode);
}
if (AnalyzerTreeView is { IsKeyboardFocusWithin: true })
{
return AnalyzerTreeView.SelectedItems.OfType<object>().All(n => n is IMemberTreeNode);
}
return MainWindow.Instance.SelectedNodes.All(n => n is IMemberTreeNode);
} }
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
if (AnalyzerTreeView is null)
{
return;
}
if (AnalyzerTreeView.IsKeyboardFocusWithin) if (AnalyzerTreeView.IsKeyboardFocusWithin)
{ {
foreach (var node in AnalyzerTreeView.SelectedItems.OfType<IMemberTreeNode>().ToArray()) foreach (var node in AnalyzerTreeView.SelectedItems.OfType<IMemberTreeNode>().ToArray())

21
ILSpy/Analyzers/AnalyzerTreeView.cs

@ -29,6 +29,7 @@ using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpy.Controls.TreeView; using ICSharpCode.ILSpy.Controls.TreeView;
using ICSharpCode.ILSpy.Util;
using ICSharpCode.ILSpyX.TreeView; using ICSharpCode.ILSpyX.TreeView;
using TomsToolbox.Wpf.Composition.Mef; using TomsToolbox.Wpf.Composition.Mef;
@ -48,25 +49,21 @@ namespace ICSharpCode.ILSpy.Analyzers
public AnalyzerTreeView() public AnalyzerTreeView()
{ {
this.ShowRoot = false; this.ShowRoot = false;
this.Root = new AnalyzerRootNode { Language = MainWindow.Instance.CurrentLanguage };
this.BorderThickness = new Thickness(0); this.BorderThickness = new Thickness(0);
ContextMenuProvider.Add(this); ContextMenuProvider.Add(this);
MainWindow.Instance.CurrentAssemblyListChanged += MainWindow_Instance_CurrentAssemblyListChanged; MessageBus<CurrentAssemblyListChangedEventArgs>.Subscribers += (sender, e) => MainWindow_Instance_CurrentAssemblyListChanged(sender, e);
DockWorkspace.Instance.PropertyChanged += DockWorkspace_PropertyChanged; MessageBus<DockWorkspaceActiveTabPageChangedEventArgs>.Subscribers += DockWorkspace_ActiveTabPageChanged;
filterSettings = MainWindow.Instance.SessionSettings.FilterSettings; filterSettings = MainWindow.Instance.SessionSettings.FilterSettings;
filterSettings.PropertyChanged += FilterSettings_PropertyChanged; filterSettings.PropertyChanged += FilterSettings_PropertyChanged;
} }
private void DockWorkspace_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) private void DockWorkspace_ActiveTabPageChanged(object sender, EventArgs e)
{ {
switch (e.PropertyName) this.Root ??= new AnalyzerRootNode { Language = MainWindow.Instance.CurrentLanguage };
{
case nameof(DockWorkspace.Instance.ActiveTabPage): filterSettings.PropertyChanged -= FilterSettings_PropertyChanged;
filterSettings.PropertyChanged -= FilterSettings_PropertyChanged; filterSettings = DockWorkspace.Instance.ActiveTabPage.FilterSettings;
filterSettings = DockWorkspace.Instance.ActiveTabPage.FilterSettings; filterSettings.PropertyChanged += FilterSettings_PropertyChanged;
filterSettings.PropertyChanged += FilterSettings_PropertyChanged;
break;
}
} }
private void FilterSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) private void FilterSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)

53
ILSpy/Docking/DockWorkspace.cs

@ -36,23 +36,23 @@ using AvalonDock.Layout.Serialization;
using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.Util;
using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpy.ViewModels;
using TomsToolbox.Wpf;
namespace ICSharpCode.ILSpy.Docking namespace ICSharpCode.ILSpy.Docking
{ {
public class DockWorkspace : INotifyPropertyChanged, ILayoutUpdateStrategy public class DockWorkspace : ObservableObject, ILayoutUpdateStrategy
{ {
private SessionSettings sessionSettings; private SessionSettings sessionSettings;
public event PropertyChangedEventHandler PropertyChanged; public static readonly DockWorkspace Instance = new();
public static DockWorkspace Instance { get; private set; }
internal DockWorkspace(MainWindow parent) private DockWorkspace()
{ {
Instance = this;
this.TabPages.CollectionChanged += Documents_CollectionChanged; this.TabPages.CollectionChanged += Documents_CollectionChanged;
parent.CurrentAssemblyListChanged += MainWindow_Instance_CurrentAssemblyListChanged; MessageBus<CurrentAssemblyListChangedEventArgs>.Subscribers += (sender, e) => MainWindow_Instance_CurrentAssemblyListChanged(sender, e);
} }
private void MainWindow_Instance_CurrentAssemblyListChanged(object sender, NotifyCollectionChangedEventArgs e) private void MainWindow_Instance_CurrentAssemblyListChanged(object sender, NotifyCollectionChangedEventArgs e)
@ -118,31 +118,31 @@ namespace ICSharpCode.ILSpy.Docking
tool.IsVisible = false; tool.IsVisible = false;
} }
private TabPageModel _activeTabPage = null; private TabPageModel activeTabPage = null;
public TabPageModel ActiveTabPage { public TabPageModel ActiveTabPage {
get { get {
return _activeTabPage; return activeTabPage;
} }
set { set {
if (_activeTabPage != value) if (!SetProperty(ref activeTabPage, value))
{
return;
}
var state = value.GetState();
if (state != null)
{ {
_activeTabPage = value; if (state.DecompiledNodes != null)
var state = value.GetState();
if (state != null)
{ {
if (state.DecompiledNodes != null) MainWindow.Instance.SelectNodes(state.DecompiledNodes,
{ inNewTabPage: false, setFocus: true, changingActiveTab: true);
MainWindow.Instance.SelectNodes(state.DecompiledNodes, }
inNewTabPage: false, setFocus: true, changingActiveTab: true); else
} {
else MainWindow.Instance.NavigateTo(new(state.ViewedUri, null));
{
MainWindow.Instance.NavigateTo(new RequestNavigateEventArgs(state.ViewedUri, null));
}
} }
RaisePropertyChanged(nameof(ActiveTabPage));
} }
MessageBus.Send(this, new DockWorkspaceActiveTabPageChangedEventArgs());
} }
} }
@ -181,11 +181,6 @@ namespace ICSharpCode.ILSpy.Docking
} }
} }
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void ShowText(AvalonEditTextOutput textOutput) public void ShowText(AvalonEditTextOutput textOutput)
{ {
ActiveTabPage.ShowTextView(textView => textView.ShowText(textOutput)); ActiveTabPage.ShowTextView(textView => textView.ShowText(textOutput));

18
ILSpy/Docking/ActiveTabPageConverter.cs → ILSpy/Docking/TabPageGuardConverter.cs

@ -21,24 +21,20 @@ using System.Windows.Data;
using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpy.ViewModels;
using TomsToolbox.Wpf.Converters;
namespace ICSharpCode.ILSpy.Docking namespace ICSharpCode.ILSpy.Docking
{ {
public class ActiveTabPageConverter : IValueConverter public class TabPageGuardConverter : ValueConverter
{ {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) protected override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{ {
if (value is TabPageModel) return value is TabPageModel ? value : Binding.DoNothing;
return value;
return Binding.DoNothing;
} }
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) protected override object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{ {
if (value is TabPageModel) return value is TabPageModel ? value : Binding.DoNothing;
return value;
return Binding.DoNothing;
} }
} }
} }

9
ILSpy/MainWindow.xaml

@ -26,8 +26,6 @@
d:DataContext="{d:DesignInstance local:MainWindowViewModel}" d:DataContext="{d:DesignInstance local:MainWindowViewModel}"
> >
<Window.Resources> <Window.Resources>
<docking:ActiveTabPageConverter x:Key="ActiveTabPageConverter"/>
<tv:SharpTreeView x:Key="AssemblyTreeView" <tv:SharpTreeView x:Key="AssemblyTreeView"
AutomationProperties.Name="Assemblies and Classes" AutomationProperties.Name="Assemblies and Classes"
SelectionChanged="TreeView_SelectionChanged" SelectionChanged="TreeView_SelectionChanged"
@ -82,6 +80,7 @@
<controls:CultureSelectionConverter x:Key="cultureSelectionConverter" /> <controls:CultureSelectionConverter x:Key="cultureSelectionConverter" />
</Window.Resources> </Window.Resources>
<b:Interaction.Behaviors> <b:Interaction.Behaviors>
<themes:WindowStyleManagerBehavior /> <themes:WindowStyleManagerBehavior />
</b:Interaction.Behaviors> </b:Interaction.Behaviors>
@ -109,12 +108,15 @@
Command="Search" Command="Search"
Executed="SearchCommandExecuted" /> Executed="SearchCommandExecuted" />
</Window.CommandBindings> </Window.CommandBindings>
<Window.InputBindings> <Window.InputBindings>
<KeyBinding Key="R" Modifiers="Control" Command="{x:Static local:ILSpyCommands.Analyze}" /> <KeyBinding Key="R" Modifiers="Control" Command="{x:Static local:ILSpyCommands.Analyze}" />
</Window.InputBindings> </Window.InputBindings>
<Window.TaskbarItemInfo> <Window.TaskbarItemInfo>
<TaskbarItemInfo /> <TaskbarItemInfo />
</Window.TaskbarItemInfo> </Window.TaskbarItemInfo>
<DockPanel> <DockPanel>
<!-- Main menu --> <!-- Main menu -->
<Menu DockPanel.Dock="Top" Name="mainMenu" Height="23" KeyboardNavigation.TabNavigation="None"> <Menu DockPanel.Dock="Top" Name="mainMenu" Height="23" KeyboardNavigation.TabNavigation="None">
@ -207,6 +209,7 @@
ItemsSource="{Binding SelectedItem.LanguageVersions, ElementName=languageComboBox, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding SelectedItem.LanguageVersions, ElementName=languageComboBox, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding Workspace.ActiveTabPage.FilterSettings.LanguageVersion, UpdateSourceTrigger=PropertyChanged}"/> SelectedItem="{Binding Workspace.ActiveTabPage.FilterSettings.LanguageVersion, UpdateSourceTrigger=PropertyChanged}"/>
</ToolBar> </ToolBar>
<!-- Update panel -->
<Border DockPanel.Dock="Top" BorderBrush="Black" BorderThickness="1" Name="updatePanel" Visibility="Collapsed"> <Border DockPanel.Dock="Top" BorderBrush="Black" BorderThickness="1" Name="updatePanel" Visibility="Collapsed">
<DockPanel KeyboardNavigation.TabNavigation="Contained"> <DockPanel KeyboardNavigation.TabNavigation="Contained">
<Button DockPanel.Dock="Right" Click="updatePanelCloseButtonClick" MinWidth="0">X</Button> <Button DockPanel.Dock="Right" Click="updatePanelCloseButtonClick" MinWidth="0">X</Button>
@ -231,7 +234,7 @@
DataContext="{Binding Workspace}" DataContext="{Binding Workspace}"
AnchorablesSource="{Binding ToolPanes}" AnchorablesSource="{Binding ToolPanes}"
DocumentsSource="{Binding TabPages}" DocumentsSource="{Binding TabPages}"
ActiveContent="{Binding ActiveTabPage, Mode=TwoWay, Converter={StaticResource ActiveTabPageConverter}}" ActiveContent="{Binding ActiveTabPage, Mode=TwoWay, Converter={docking:TabPageGuardConverter}}"
AllowMixedOrientation="True"> AllowMixedOrientation="True">
<avalondock:DockingManager.DocumentHeaderTemplate> <avalondock:DockingManager.DocumentHeaderTemplate>

44
ILSpy/MainWindow.xaml.cs

@ -42,7 +42,6 @@ using ICSharpCode.Decompiler.Documentation;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.ILSpy.Analyzers;
using ICSharpCode.ILSpy.AppEnv; using ICSharpCode.ILSpy.AppEnv;
using ICSharpCode.ILSpy.Commands; using ICSharpCode.ILSpy.Commands;
using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Docking;
@ -57,6 +56,7 @@ using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpyX.FileLoaders; using ICSharpCode.ILSpyX.FileLoaders;
using ICSharpCode.ILSpyX.Settings; using ICSharpCode.ILSpyX.Settings;
using ICSharpCode.ILSpy.Controls.TreeView; using ICSharpCode.ILSpy.Controls.TreeView;
using ICSharpCode.ILSpy.Util;
using ICSharpCode.ILSpyX.Extensions; using ICSharpCode.ILSpyX.Extensions;
using Microsoft.Win32; using Microsoft.Win32;
@ -130,7 +130,7 @@ namespace ICSharpCode.ILSpy
this.Icon = Images.ILSpyIcon; this.Icon = Images.ILSpyIcon;
this.DataContext = new MainWindowViewModel { this.DataContext = new MainWindowViewModel {
Workspace = new DockWorkspace(this), Workspace = DockWorkspace.Instance,
SessionSettings = sessionSettings, SessionSettings = sessionSettings,
AssemblyListManager = AssemblyListManager AssemblyListManager = AssemblyListManager
}; };
@ -147,7 +147,7 @@ namespace ICSharpCode.ILSpy
sessionSettings.PropertyChanged += SessionSettings_PropertyChanged; sessionSettings.PropertyChanged += SessionSettings_PropertyChanged;
filterSettings = sessionSettings.FilterSettings; filterSettings = sessionSettings.FilterSettings;
filterSettings.PropertyChanged += filterSettings_PropertyChanged; filterSettings.PropertyChanged += filterSettings_PropertyChanged;
DockWorkspace.Instance.PropertyChanged += DockWorkspace_PropertyChanged; MessageBus<DockWorkspaceActiveTabPageChangedEventArgs>.Subscribers += DockWorkspace_ActiveTabPageChanged;
InitMainMenu(); InitMainMenu();
InitWindowMenu(); InitWindowMenu();
InitToolbar(); InitToolbar();
@ -157,25 +157,20 @@ namespace ICSharpCode.ILSpy
this.Loaded += MainWindow_Loaded; this.Loaded += MainWindow_Loaded;
} }
private void DockWorkspace_PropertyChanged(object sender, PropertyChangedEventArgs e) private void DockWorkspace_ActiveTabPageChanged(object sender, EventArgs e)
{ {
switch (e.PropertyName) DockWorkspace dock = DockWorkspace.Instance;
{ filterSettings.PropertyChanged -= filterSettings_PropertyChanged;
case nameof(DockWorkspace.Instance.ActiveTabPage): filterSettings = dock.ActiveTabPage.FilterSettings;
DockWorkspace dock = DockWorkspace.Instance; filterSettings.PropertyChanged += filterSettings_PropertyChanged;
filterSettings.PropertyChanged -= filterSettings_PropertyChanged;
filterSettings = dock.ActiveTabPage.FilterSettings;
filterSettings.PropertyChanged += filterSettings_PropertyChanged;
var windowMenuItem = mainMenu.Items.OfType<MenuItem>().First(m => (string)m.Tag == nameof(Properties.Resources._Window)); var windowMenuItem = mainMenu.Items.OfType<MenuItem>().First(m => (string)m.Tag == nameof(Properties.Resources._Window));
foreach (MenuItem menuItem in windowMenuItem.Items.OfType<MenuItem>()) foreach (MenuItem menuItem in windowMenuItem.Items.OfType<MenuItem>())
{ {
if (menuItem.IsCheckable && menuItem.Tag is TabPageModel) if (menuItem.IsCheckable && menuItem.Tag is TabPageModel)
{ {
menuItem.IsChecked = menuItem.Tag == dock.ActiveTabPage; menuItem.IsChecked = menuItem.Tag == dock.ActiveTabPage;
} }
}
break;
} }
} }
@ -359,7 +354,7 @@ namespace ICSharpCode.ILSpy
#endregion #endregion
#region Tool Pane extensibility #region Tool Pane extensibility
private void InitToolPanes() private void InitToolPanes()
{ {
var toolPanes = App.ExportProvider.GetExportedValues<ToolPaneModel>("ToolPane"); var toolPanes = App.ExportProvider.GetExportedValues<ToolPaneModel>("ToolPane");
@ -632,8 +627,6 @@ namespace ICSharpCode.ILSpy
get { return assemblyList; } get { return assemblyList; }
} }
public event NotifyCollectionChangedEventHandler CurrentAssemblyListChanged;
List<LoadedAssembly> commandLineLoadedAssemblies = new List<LoadedAssembly>(); List<LoadedAssembly> commandLineLoadedAssemblies = new List<LoadedAssembly>();
internal async Task HandleSingleInstanceCommandLineArguments(string[] args) internal async Task HandleSingleInstanceCommandLineArguments(string[] args)
@ -1038,7 +1031,8 @@ namespace ICSharpCode.ILSpy
nd => nd.AncestorsAndSelf().OfType<AssemblyTreeNode>().Any( nd => nd.AncestorsAndSelf().OfType<AssemblyTreeNode>().Any(
a => oldAssemblies.Contains(a.LoadedAssembly)))); a => oldAssemblies.Contains(a.LoadedAssembly))));
} }
CurrentAssemblyListChanged?.Invoke(this, e);
MessageBus.Send(this, new CurrentAssemblyListChangedEventArgs(e));
} }
void LoadInitialAssemblies() void LoadInitialAssemblies()
@ -1528,8 +1522,6 @@ namespace ICSharpCode.ILSpy
public Language CurrentLanguage => DockWorkspace.Instance.ActiveTabPage.FilterSettings.Language; public Language CurrentLanguage => DockWorkspace.Instance.ActiveTabPage.FilterSettings.Language;
public LanguageVersion CurrentLanguageVersion => DockWorkspace.Instance.ActiveTabPage.FilterSettings.LanguageVersion; public LanguageVersion CurrentLanguageVersion => DockWorkspace.Instance.ActiveTabPage.FilterSettings.LanguageVersion;
public bool SupportsLanguageSwitching => DockWorkspace.Instance.ActiveTabPage.SupportsLanguageSwitching;
public event SelectionChangedEventHandler SelectionChanged; public event SelectionChangedEventHandler SelectionChanged;
public IEnumerable<ILSpyTreeNode> SelectedNodes { public IEnumerable<ILSpyTreeNode> SelectedNodes {

3
ILSpy/Search/SearchPane.cs

@ -35,6 +35,7 @@ using System.Windows.Threading;
using ICSharpCode.ILSpy.AppEnv; using ICSharpCode.ILSpy.AppEnv;
using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.Util;
using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpyX.Extensions; using ICSharpCode.ILSpyX.Extensions;
@ -82,7 +83,7 @@ namespace ICSharpCode.ILSpy.Search
searchModeComboBox.Items.Add(new { Image = Images.Namespace, Name = "Namespace" }); searchModeComboBox.Items.Add(new { Image = Images.Namespace, Name = "Namespace" });
ContextMenuProvider.Add(listBox); ContextMenuProvider.Add(listBox);
MainWindow.Instance.CurrentAssemblyListChanged += MainWindow_Instance_CurrentAssemblyListChanged; MessageBus<CurrentAssemblyListChangedEventArgs>.Subscribers += (sender, e) => MainWindow_Instance_CurrentAssemblyListChanged(sender, e);
filterSettings = MainWindow.Instance.SessionSettings.FilterSettings; filterSettings = MainWindow.Instance.SessionSettings.FilterSettings;
CompositionTarget.Rendering += UpdateResults; CompositionTarget.Rendering += UpdateResults;

55
ILSpy/Util/MessageBus.cs

@ -0,0 +1,55 @@
using System;
using System.Collections.Specialized;
using TomsToolbox.Essentials;
namespace ICSharpCode.ILSpy.Util
{
public static class MessageBus
{
public static void Send<T>(object sender, T e)
where T : EventArgs
{
MessageBus<T>.Send(sender, e);
}
}
/// <summary>
/// Simple, minimalistic message bus.
/// </summary>
/// <typeparam name="T">The type of the message event arguments</typeparam>
public static class MessageBus<T>
where T : EventArgs
{
private static readonly WeakEventSource<T> Subscriptions = new();
public static event EventHandler<T> Subscribers {
add => Subscriptions.Subscribe(value);
remove => Subscriptions.Unsubscribe(value);
}
public static void Send(object sender, T e)
{
Subscriptions.Raise(sender, e);
}
}
public abstract class WrappedEventArgs<T> : EventArgs
{
private readonly T inner;
protected WrappedEventArgs(T inner)
{
this.inner = inner;
}
public static implicit operator T(WrappedEventArgs<T> outer)
{
return outer.inner;
}
}
public class CurrentAssemblyListChangedEventArgs(NotifyCollectionChangedEventArgs e) : WrappedEventArgs<NotifyCollectionChangedEventArgs>(e);
public class DockWorkspaceActiveTabPageChangedEventArgs : EventArgs;
}

16
ILSpy/Views/DebugSteps.xaml.cs

@ -8,6 +8,7 @@ using System.Windows.Input;
using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.IL.Transforms; using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.Util;
using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.ILSpy.ViewModels;
using TomsToolbox.Wpf.Composition.Mef; using TomsToolbox.Wpf.Composition.Mef;
@ -35,7 +36,7 @@ namespace ICSharpCode.ILSpy
InitializeComponent(); InitializeComponent();
#if DEBUG #if DEBUG
DockWorkspace.Instance.PropertyChanged += DockWorkspace_PropertyChanged; MessageBus<DockWorkspaceActiveTabPageChangedEventArgs>.Subscribers += DockWorkspace_ActiveTabPageChanged;
filterSettings = DockWorkspace.Instance.ActiveTabPage.FilterSettings; filterSettings = DockWorkspace.Instance.ActiveTabPage.FilterSettings;
filterSettings.PropertyChanged += FilterSettings_PropertyChanged; filterSettings.PropertyChanged += FilterSettings_PropertyChanged;
MainWindow.Instance.SelectionChanged += SelectionChanged; MainWindow.Instance.SelectionChanged += SelectionChanged;
@ -50,16 +51,11 @@ namespace ICSharpCode.ILSpy
#endif #endif
} }
private void DockWorkspace_PropertyChanged(object sender, PropertyChangedEventArgs e) private void DockWorkspace_ActiveTabPageChanged(object sender, EventArgs e)
{ {
switch (e.PropertyName) filterSettings.PropertyChanged -= FilterSettings_PropertyChanged;
{ filterSettings = DockWorkspace.Instance.ActiveTabPage.FilterSettings;
case nameof(DockWorkspace.Instance.ActiveTabPage): filterSettings.PropertyChanged += FilterSettings_PropertyChanged;
filterSettings.PropertyChanged -= FilterSettings_PropertyChanged;
filterSettings = DockWorkspace.Instance.ActiveTabPage.FilterSettings;
filterSettings.PropertyChanged += FilterSettings_PropertyChanged;
break;
}
} }
private void WritingOptions_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) private void WritingOptions_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)

Loading…
Cancel
Save