Browse Source

Refactor OptionsDialog to use MVVM style

pull/3274/head
tom-englert 8 months ago committed by tom-englert
parent
commit
ca687e2394
  1. 4
      ILSpy.ReadyToRun/ReadyToRunOptionPage.xaml.cs
  2. 4
      ILSpy/Options/DecompilerSettingsPanel.xaml.cs
  3. 4
      ILSpy/Options/DisplaySettingsPanel.xaml.cs
  4. 4
      ILSpy/Options/MiscSettingsPanel.xaml.cs
  5. 48
      ILSpy/Options/OptionsDialog.xaml
  6. 73
      ILSpy/Options/OptionsDialog.xaml.cs
  7. 71
      ILSpy/Options/OptionsDialogViewModel.cs
  8. 5
      TestPlugin/CustomOptionPage.xaml.cs

4
ILSpy.ReadyToRun/ReadyToRunOptionPage.xaml.cs

@ -26,7 +26,7 @@ using ICSharpCode.ILSpyX.Settings; @@ -26,7 +26,7 @@ using ICSharpCode.ILSpyX.Settings;
namespace ICSharpCode.ILSpy.ReadyToRun
{
[ExportOptionPage(Title = nameof(global::ILSpy.ReadyToRun.Properties.Resources.ReadyToRun), Order = 40)]
[ExportOptionPage(Order = 40)]
[PartCreationPolicy(CreationPolicy.NonShared)]
partial class ReadyToRunOptionPage : UserControl, IOptionPage
{
@ -35,6 +35,8 @@ namespace ICSharpCode.ILSpy.ReadyToRun @@ -35,6 +35,8 @@ namespace ICSharpCode.ILSpy.ReadyToRun
InitializeComponent();
}
public string Title => global::ILSpy.ReadyToRun.Properties.Resources.ReadyToRun;
public void Load(ILSpySettings settings)
{
Options s = new Options();

4
ILSpy/Options/DecompilerSettingsPanel.xaml.cs

@ -26,7 +26,7 @@ namespace ICSharpCode.ILSpy.Options @@ -26,7 +26,7 @@ namespace ICSharpCode.ILSpy.Options
/// <summary>
/// Interaction logic for DecompilerSettingsPanel.xaml
/// </summary>
[ExportOptionPage(Title = nameof(Properties.Resources.Decompiler), Order = 10)]
[ExportOptionPage(Order = 10)]
[PartCreationPolicy(CreationPolicy.NonShared)]
internal partial class DecompilerSettingsPanel : IOptionPage
{
@ -35,6 +35,8 @@ namespace ICSharpCode.ILSpy.Options @@ -35,6 +35,8 @@ namespace ICSharpCode.ILSpy.Options
InitializeComponent();
}
public string Title => Properties.Resources.Decompiler;
public static Decompiler.DecompilerSettings LoadDecompilerSettings(ILSpySettings settings)
{
return ISettingsProvider.LoadDecompilerSettings(settings);

4
ILSpy/Options/DisplaySettingsPanel.xaml.cs

@ -34,7 +34,7 @@ namespace ICSharpCode.ILSpy.Options @@ -34,7 +34,7 @@ namespace ICSharpCode.ILSpy.Options
/// <summary>
/// Interaction logic for DisplaySettingsPanel.xaml
/// </summary>
[ExportOptionPage(Title = nameof(Properties.Resources.Display), Order = 20)]
[ExportOptionPage(Order = 20)]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class DisplaySettingsPanel : UserControl, IOptionPage
{
@ -67,6 +67,8 @@ namespace ICSharpCode.ILSpy.Options @@ -67,6 +67,8 @@ namespace ICSharpCode.ILSpy.Options
);
}
public string Title => Properties.Resources.Display;
public void Load(ILSpySettings settings)
{
this.DataContext = LoadDisplaySettings(settings);

4
ILSpy/Options/MiscSettingsPanel.xaml.cs

@ -27,7 +27,7 @@ namespace ICSharpCode.ILSpy.Options @@ -27,7 +27,7 @@ namespace ICSharpCode.ILSpy.Options
/// <summary>
/// Interaction logic for MiscSettingsPanel.xaml
/// </summary>
[ExportOptionPage(Title = nameof(Properties.Resources.Misc), Order = 30)]
[ExportOptionPage(Order = 30)]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class MiscSettingsPanel : UserControl, IOptionPage
{
@ -36,6 +36,8 @@ namespace ICSharpCode.ILSpy.Options @@ -36,6 +36,8 @@ namespace ICSharpCode.ILSpy.Options
InitializeComponent();
}
public string Title => Properties.Resources.Misc;
public void Load(ILSpySettings settings)
{
this.DataContext = new MiscSettingsViewModel(SettingsService.Instance.MiscSettings);

48
ILSpy/Options/OptionsDialog.xaml

@ -1,35 +1,43 @@ @@ -1,35 +1,43 @@
<Window x:Class="ICSharpCode.ILSpy.Options.OptionsDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties"
xmlns:options="clr-namespace:ICSharpCode.ILSpy.Options"
Style="{DynamicResource DialogWindow}"
xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties"
xmlns:options="clr-namespace:ICSharpCode.ILSpy.Options"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:toms="urn:TomsToolbox"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance options:OptionsDialogViewModel}"
Style="{StaticResource DialogWindow}"
WindowStartupLocation="CenterOwner"
ResizeMode="CanResizeWithGrip"
Title="{x:Static properties:Resources.Options}" Height="500" Width="600">
<Grid>
<Grid.RowDefinitions>
<RowDefinition
Height="1*" />
<RowDefinition
Height="Auto" />
</Grid.RowDefinitions>
<TabControl Name="tabControl" SelectedValuePath="Content">
<DockPanel>
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Right" Margin="12,8">
<Button Margin="2,0"
Command="{Binding ResetDefaultsCommand}"
Content="{x:Static properties:Resources.ResetToDefaults}" />
<Button IsDefault="True" Margin="2,0"
toms:Button.DialogResult="true"
Command="{Binding CommitCommand}"
Content="{x:Static properties:Resources.OK}" />
<Button IsCancel="True" Margin="2,0"
Content="{x:Static properties:Resources.Cancel}" />
</StackPanel>
<TabControl ItemsSource="{Binding OptionPages}"
SelectedIndex="0"
SelectedValuePath="Content"
SelectedValue="{Binding SelectedPage}">
<TabControl.ItemTemplate>
<DataTemplate DataType="options:TabItemViewModel">
<TextBlock Text="{Binding Header}" />
<DataTemplate DataType="options:OptionsItemViewModel">
<TextBlock Text="{Binding Title}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate DataType="options:TabItemViewModel">
<DataTemplate DataType="options:OptionsItemViewModel">
<ContentPresenter Content="{Binding Content}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right" Margin="12,8">
<Button Margin="2,0" Name="defaultsButton" Click="DefaultsButton_Click" Content="{x:Static properties:Resources.ResetToDefaults}" />
<Button IsDefault="True" Margin="2,0" Name="okButton" Click="OKButton_Click" Content="{x:Static properties:Resources.OK}" />
<Button IsCancel="True" Margin="2,0" Content="{x:Static properties:Resources.Cancel}" />
</StackPanel>
</Grid>
</DockPanel>
</Window>

73
ILSpy/Options/OptionsDialog.xaml.cs

@ -18,103 +18,42 @@ @@ -18,103 +18,42 @@
using System;
using System.ComponentModel.Composition;
using System.Linq;
using System.Windows;
using System.Xml.Linq;
using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpyX.Settings;
using TomsToolbox.Composition;
namespace ICSharpCode.ILSpy.Options
{
public class TabItemViewModel
{
public TabItemViewModel(string header, UIElement content)
{
Header = header;
Content = content;
}
public string Header { get; }
public UIElement Content { get; }
}
/// <summary>
/// Interaction logic for OptionsDialog.xaml
/// </summary>
public partial class OptionsDialog : Window
public sealed partial class OptionsDialog
{
readonly IExport<UIElement, IOptionsMetadata>[] optionPages;
public OptionsDialog()
{
DataContext = new OptionsDialogViewModel();
InitializeComponent();
var ep = App.ExportProvider;
this.optionPages = ep.GetExports<UIElement, IOptionsMetadata>("OptionPages").ToArray();
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);
tabControl.Items.Add(tabItem);
IOptionPage page = optionPage.Value as IOptionPage;
if (page != null)
page.Load(settings);
}
}
void OKButton_Click(object sender, RoutedEventArgs e)
{
SettingsService.Instance.SpySettings.Update(
root => {
foreach (var optionPage in optionPages)
{
IOptionPage page = optionPage.Value as IOptionPage;
if (page != null)
page.Save(root);
}
});
this.DialogResult = true;
Close();
}
private void DefaultsButton_Click(object sender, RoutedEventArgs e)
{
if (MessageBox.Show(Properties.Resources.ResetToDefaultsConfirmationMessage, "ILSpy", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
var page = tabControl.SelectedValue as IOptionPage;
if (page != null)
page.LoadDefaults();
}
}
}
public interface IOptionsMetadata
{
string Title { get; }
int Order { get; }
}
public interface IOptionPage
{
string Title { get; }
void Load(ILSpySettings settings);
void Save(XElement root);
void LoadDefaults();
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ExportOptionPageAttribute : ExportAttribute
[AttributeUsage(AttributeTargets.Class)]
public sealed class ExportOptionPageAttribute() : ExportAttribute("OptionPages", typeof(IOptionPage)), IOptionsMetadata
{
public ExportOptionPageAttribute() : base("OptionPages", typeof(UIElement))
{ }
public string Title { get; set; }
public int Order { get; set; }
}
@ -125,7 +64,7 @@ namespace ICSharpCode.ILSpy.Options @@ -125,7 +64,7 @@ namespace ICSharpCode.ILSpy.Options
public override void Execute(object parameter)
{
OptionsDialog dlg = new() {
Owner = MainWindow.Instance
Owner = MainWindow.Instance,
};
if (dlg.ShowDialog() == true)
{

71
ILSpy/Options/OptionsDialogViewModel.cs

@ -0,0 +1,71 @@ @@ -0,0 +1,71 @@
using System.Linq;
using System.Windows;
using System.Windows.Input;
using TomsToolbox.Essentials;
using TomsToolbox.Wpf;
#nullable enable
namespace ICSharpCode.ILSpy.Options
{
public class OptionsItemViewModel(IOptionPage content) : ObservableObject
{
public string Title { get; } = content.Title;
public IOptionPage Content { get; } = content;
}
public class OptionsDialogViewModel : ObservableObject
{
private IOptionPage? selectedPage;
private readonly IOptionPage[] optionPages = App.ExportProvider.GetExports<IOptionPage, IOptionsMetadata>("OptionPages")
.OrderBy(page => page.Metadata?.Order)
.Select(item => item.Value)
.ExceptNullItems()
.ToArray();
public OptionsDialogViewModel()
{
var settings = SettingsService.Instance.SpySettings;
foreach (var optionPage in optionPages)
{
optionPage.Load(settings);
}
OptionPages = optionPages.Select(page => new OptionsItemViewModel(page)).ToArray();
SelectedPage = optionPages.FirstOrDefault();
}
public OptionsItemViewModel[] OptionPages { get; }
public IOptionPage? SelectedPage {
get => selectedPage;
set => SetProperty(ref selectedPage, value);
}
public ICommand CommitCommand => new DelegateCommand(Commit);
public ICommand ResetDefaultsCommand => new DelegateCommand(ResetDefaults);
private void ResetDefaults()
{
if (MessageBox.Show(Properties.Resources.ResetToDefaultsConfirmationMessage, "ILSpy", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
SelectedPage?.LoadDefaults();
}
}
private void Commit()
{
SettingsService.Instance.SpySettings.Update(root => {
foreach (var optionPage in optionPages)
{
optionPage.Save(root);
}
});
}
}
}

5
TestPlugin/CustomOptionPage.xaml.cs

@ -6,13 +6,12 @@ using System.ComponentModel.Composition; @@ -6,13 +6,12 @@ using System.ComponentModel.Composition;
using System.Windows.Controls;
using System.Xml.Linq;
using ICSharpCode.ILSpy;
using ICSharpCode.ILSpy.Options;
using ICSharpCode.ILSpyX.Settings;
namespace TestPlugin
{
[ExportOptionPage(Title = "TestPlugin", Order = 0)]
[ExportOptionPage(Order = 0)]
[PartCreationPolicy(CreationPolicy.NonShared)]
partial class CustomOptionPage : UserControl, IOptionPage
{
@ -23,6 +22,8 @@ namespace TestPlugin @@ -23,6 +22,8 @@ namespace TestPlugin
InitializeComponent();
}
public string Title => "TestPlugin";
public void Load(ILSpySettings settings)
{
// For loading options, use ILSpySetting's indexer.

Loading…
Cancel
Save