diff --git a/ILSpy/Options/DecompilerSettingsPanel.xaml b/ILSpy/Options/DecompilerSettingsPanel.xaml
index f257d8654..2078217e4 100644
--- a/ILSpy/Options/DecompilerSettingsPanel.xaml
+++ b/ILSpy/Options/DecompilerSettingsPanel.xaml
@@ -7,13 +7,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:options="clr-namespace:ICSharpCode.ILSpy.Options"
d:DataContext="{d:DesignInstance options:DecompilerSettingsViewModel}">
-
-
-
-
-
-
-
@@ -24,33 +17,26 @@
-
-
-
-
-
-
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ILSpy/Options/DecompilerSettingsPanel.xaml.cs b/ILSpy/Options/DecompilerSettingsPanel.xaml.cs
index aec4ced54..9f542f243 100644
--- a/ILSpy/Options/DecompilerSettingsPanel.xaml.cs
+++ b/ILSpy/Options/DecompilerSettingsPanel.xaml.cs
@@ -16,12 +16,6 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
-using System.ComponentModel;
-using System.Linq;
-using System.Reflection;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
using System.Xml.Linq;
using ICSharpCode.ILSpyX.Settings;
@@ -32,7 +26,7 @@ namespace ICSharpCode.ILSpy.Options
/// Interaction logic for DecompilerSettingsPanel.xaml
///
[ExportOptionPage(Title = nameof(Properties.Resources.Decompiler), Order = 10)]
- internal partial class DecompilerSettingsPanel : UserControl, IOptionPage
+ internal partial class DecompilerSettingsPanel : IOptionPage
{
public DecompilerSettingsPanel()
{
@@ -59,58 +53,9 @@ namespace ICSharpCode.ILSpy.Options
MainWindow.Instance.AssemblyListManager.UseDebugSymbols = newSettings.UseDebugSymbols;
}
- private void OnGroupChecked(object sender, RoutedEventArgs e)
- {
- CheckGroup((CollectionViewGroup)((CheckBox)sender).DataContext, true);
- }
- private void OnGroupUnchecked(object sender, RoutedEventArgs e)
- {
- CheckGroup((CollectionViewGroup)((CheckBox)sender).DataContext, false);
- }
-
- void CheckGroup(CollectionViewGroup group, bool value)
- {
- foreach (var item in group.Items)
- {
- switch (item)
- {
- case CollectionViewGroup subGroup:
- CheckGroup(subGroup, value);
- break;
- case CSharpDecompilerSetting setting:
- setting.IsEnabled = value;
- break;
- }
- }
- }
-
- bool IsGroupChecked(CollectionViewGroup group)
- {
- bool value = true;
- foreach (var item in group.Items)
- {
- switch (item)
- {
- case CollectionViewGroup subGroup:
- value = value && IsGroupChecked(subGroup);
- break;
- case CSharpDecompilerSetting setting:
- value = value && setting.IsEnabled;
- break;
- }
- }
- return value;
- }
-
- private void OnGroupLoaded(object sender, RoutedEventArgs e)
- {
- CheckBox checkBox = (CheckBox)sender;
- checkBox.IsChecked = IsGroupChecked((CollectionViewGroup)checkBox.DataContext);
- }
-
public void LoadDefaults()
{
- MainWindow.Instance.CurrentDecompilerSettings = new Decompiler.DecompilerSettings();
+ MainWindow.Instance.CurrentDecompilerSettings = new();
this.DataContext = new DecompilerSettingsViewModel(MainWindow.Instance.CurrentDecompilerSettings);
}
}
diff --git a/ILSpy/Options/DecompilerSettingsViewModel.cs b/ILSpy/Options/DecompilerSettingsViewModel.cs
index b7ce36fbe..3a574cca9 100644
--- a/ILSpy/Options/DecompilerSettingsViewModel.cs
+++ b/ILSpy/Options/DecompilerSettingsViewModel.cs
@@ -16,83 +16,120 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
+using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
-using System.Runtime.CompilerServices;
using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TreeNodes;
+using TomsToolbox.Wpf;
+
namespace ICSharpCode.ILSpy.Options
{
- public class DecompilerSettingsViewModel : INotifyPropertyChanged
+ public sealed class DecompilerSettingsViewModel : ObservableObjectBase
{
- public CSharpDecompilerSetting[] Settings { get; set; }
+ public DecompilerSettingsGroupViewModel[] Settings { get; }
public DecompilerSettingsViewModel(Decompiler.DecompilerSettings settings)
{
Settings = typeof(Decompiler.DecompilerSettings).GetProperties()
.Where(p => p.GetCustomAttribute()?.Browsable != false)
- .Select(p => new CSharpDecompilerSetting(p) { IsEnabled = (bool)p.GetValue(settings) })
+ .Select(p => new DecompilerSettingsItemViewModel(p) { IsEnabled = p.GetValue(settings) is true })
.OrderBy(item => item.Category, NaturalStringComparer.Instance)
- .ThenBy(item => item.Description)
+ .GroupBy(p => p.Category)
+ .Select(g => new DecompilerSettingsGroupViewModel(g.Key, g.OrderBy(i => i.Description).ToArray()))
.ToArray();
}
- public event PropertyChangedEventHandler PropertyChanged;
-
- protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
- {
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
- }
-
public Decompiler.DecompilerSettings ToDecompilerSettings()
{
var settings = new Decompiler.DecompilerSettings();
- foreach (var item in Settings)
+
+ foreach (var item in Settings.SelectMany(group => group.Settings))
{
item.Property.SetValue(settings, item.IsEnabled);
}
+
return settings;
}
}
- public class CSharpDecompilerSetting : INotifyPropertyChanged
+
+ public sealed class DecompilerSettingsGroupViewModel : ObservableObjectBase
{
- bool isEnabled;
+ private bool? _areAllItemsChecked;
- public CSharpDecompilerSetting(PropertyInfo p)
+ public DecompilerSettingsGroupViewModel(string category, DecompilerSettingsItemViewModel[] settings)
{
- this.Property = p;
- this.Category = GetResourceString(p.GetCustomAttribute()?.Category ?? Resources.Other);
- this.Description = GetResourceString(p.GetCustomAttribute()?.Description ?? p.Name);
- }
+ Settings = settings;
+ Category = category;
- public PropertyInfo Property { get; }
+ _areAllItemsChecked = GetAreAllItemsChecked(Settings);
- public bool IsEnabled {
- get => isEnabled;
+ foreach (DecompilerSettingsItemViewModel viewModel in settings)
+ {
+ viewModel.PropertyChanged += Item_PropertyChanged;
+ }
+ }
+
+ public bool? AreAllItemsChecked {
+ get => _areAllItemsChecked;
set {
- if (value != isEnabled)
+ SetProperty(ref _areAllItemsChecked, value);
+
+ if (!value.HasValue)
+ return;
+
+ foreach (var setting in Settings)
{
- isEnabled = value;
- OnPropertyChanged();
+ setting.IsEnabled = value.Value;
}
}
}
- public string Description { get; set; }
+ public string Category { get; }
- public string Category { get; set; }
+ public DecompilerSettingsItemViewModel[] Settings { get; }
- public event PropertyChangedEventHandler PropertyChanged;
+ private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof(DecompilerSettingsItemViewModel.IsEnabled))
+ {
+ AreAllItemsChecked = GetAreAllItemsChecked(Settings);
+ }
+ }
- protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
+ private static bool? GetAreAllItemsChecked(ICollection settings)
{
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ var numberOfEnabledItems = settings.Count(item => item.IsEnabled);
+
+ if (numberOfEnabledItems == settings.Count)
+ return true;
+
+ if (numberOfEnabledItems == 0)
+ return false;
+
+ return null;
+ }
+ }
+
+ public sealed class DecompilerSettingsItemViewModel(PropertyInfo property) : ObservableObjectBase
+ {
+ private bool _isEnabled;
+
+ public PropertyInfo Property { get; } = property;
+
+ public bool IsEnabled {
+ get => _isEnabled;
+ set => SetProperty(ref _isEnabled, value);
}
- static string GetResourceString(string key)
+ public string Description { get; set; } = GetResourceString(property.GetCustomAttribute()?.Description ?? property.Name);
+
+ public string Category { get; set; } = GetResourceString(property.GetCustomAttribute()?.Category ?? Resources.Other);
+
+ private static string GetResourceString(string key)
{
var str = !string.IsNullOrEmpty(key) ? Resources.ResourceManager.GetString(key) : null;
return string.IsNullOrEmpty(key) || string.IsNullOrEmpty(str) ? key : str;