Browse Source

Implement PropertyGrid multiple vm editing

pull/333/head
Ionite 12 months ago
parent
commit
9dac1c4850
No known key found for this signature in database
  1. 55
      StabilityMatrix.Avalonia/Controls/PropertyGrid/BetterPropertyGrid.cs
  2. 100
      StabilityMatrix.Avalonia/Controls/StackExpander.axaml
  3. 17
      StabilityMatrix.Avalonia/DesignData/DesignData.cs
  4. 10
      StabilityMatrix.Avalonia/DesignData/MockPropertyGridObject.cs
  5. 10
      StabilityMatrix.Avalonia/ViewModels/Dialogs/PropertyGridViewModel.cs
  6. 49
      StabilityMatrix.Avalonia/Views/Dialogs/PropertyGridDialog.axaml
  7. 43
      StabilityMatrix.Avalonia/Views/Dialogs/PropertyGridDialog.axaml.cs

55
StabilityMatrix.Avalonia/Controls/PropertyGrid/BetterPropertyGrid.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Avalonia;
using Avalonia.PropertyGrid.Services; using Avalonia.PropertyGrid.Services;
using JetBrains.Annotations; using JetBrains.Annotations;
using PropertyModels.ComponentModel; using PropertyModels.ComponentModel;
@ -14,10 +15,56 @@ public class BetterPropertyGrid : global::Avalonia.PropertyGrid.Controls.Propert
{ {
protected override Type StyleKeyOverride => typeof(global::Avalonia.PropertyGrid.Controls.PropertyGrid); protected override Type StyleKeyOverride => typeof(global::Avalonia.PropertyGrid.Controls.PropertyGrid);
public static readonly StyledProperty<IEnumerable<string>> ExcludedCategoriesProperty = AvaloniaProperty.Register<
BetterPropertyGrid,
IEnumerable<string>
>("ExcludedCategories");
public IEnumerable<string> ExcludedCategories
{
get => GetValue(ExcludedCategoriesProperty);
set => SetValue(ExcludedCategoriesProperty, value);
}
public static readonly StyledProperty<IEnumerable<string>> IncludedCategoriesProperty = AvaloniaProperty.Register<
BetterPropertyGrid,
IEnumerable<string>
>("IncludedCategories");
public IEnumerable<string> IncludedCategories
{
get => GetValue(IncludedCategoriesProperty);
set => SetValue(IncludedCategoriesProperty, value);
}
static BetterPropertyGrid() static BetterPropertyGrid()
{ {
// Initialize localization and name resolver // Initialize localization and name resolver
LocalizationService.Default.AddExtraService(new PropertyGridLocalizationService()); LocalizationService.Default.AddExtraService(new PropertyGridLocalizationService());
ExcludedCategoriesProperty
.Changed
.AddClassHandler<BetterPropertyGrid>(
(grid, args) =>
{
if (args.NewValue is IEnumerable<string> excludedCategories)
{
grid.FilterExcludeCategories(excludedCategories);
}
}
);
IncludedCategoriesProperty
.Changed
.AddClassHandler<BetterPropertyGrid>(
(grid, args) =>
{
if (args.NewValue is IEnumerable<string> includedCategories)
{
grid.FilterIncludeCategories(includedCategories);
}
}
);
} }
public void FilterExcludeCategories(IEnumerable<string> excludedCategories) public void FilterExcludeCategories(IEnumerable<string> excludedCategories)
@ -55,9 +102,13 @@ public class BetterPropertyGrid : global::Avalonia.PropertyGrid.Controls.Propert
categoryFilter.BeginUpdate(); categoryFilter.BeginUpdate();
// Uncheck All and check Misc by default // Uncheck non-included categories
foreach (var mask in categoryFilter.Masks.Where(m => !includeCategories.Contains(m)))
{
categoryFilter.UnCheck(mask);
}
categoryFilter.UnCheck(categoryFilter.All); categoryFilter.UnCheck(categoryFilter.All);
categoryFilter.Check("Misc");
// Check included categories // Check included categories
foreach (var mask in includeCategories) foreach (var mask in includeCategories)

100
StabilityMatrix.Avalonia/Controls/StackExpander.axaml

@ -1,85 +1,97 @@
<Styles xmlns="https://github.com/avaloniaui" <Styles
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="https://github.com/avaloniaui"
xmlns:controls="using:StabilityMatrix.Avalonia.Controls" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData" xmlns:controls="using:StabilityMatrix.Avalonia.Controls"
xmlns:vmInference="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Inference" xmlns:fluentIcons="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia"
xmlns:local="clr-namespace:StabilityMatrix.Avalonia" xmlns:local="clr-namespace:StabilityMatrix.Avalonia"
xmlns:fluentIcons="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia" xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData"
x:DataType="vmInference:StackExpanderViewModel"> xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:vmInference="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Inference"
x:DataType="vmInference:StackExpanderViewModel">
<Design.PreviewWith> <Design.PreviewWith>
<Grid Width="500" Height="800"> <Grid Width="500" Height="800">
<StackPanel> <StackPanel>
<controls:StackExpander <controls:StackExpander DataContext="{x:Static mocks:DesignData.StackExpanderViewModel}" />
DataContext="{x:Static mocks:DesignData.StackExpanderViewModel}"/>
<controls:StackExpander DataContext="{x:Static mocks:DesignData.StackExpanderViewModel2}" />
</StackPanel> </StackPanel>
</Grid> </Grid>
</Design.PreviewWith> </Design.PreviewWith>
<Style Selector="controls|StackExpander"> <Style Selector="controls|StackExpander">
<!-- Set Defaults --> <!-- Set Defaults -->
<Setter Property="HorizontalAlignment" Value="Stretch"/> <Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<Expander <Expander
VerticalContentAlignment="Top"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
HorizontalContentAlignment="Stretch" HorizontalContentAlignment="Stretch"
VerticalAlignment="{TemplateBinding VerticalAlignment}"> VerticalContentAlignment="Top">
<Expander.Styles> <Expander.Styles>
<Style Selector="Expander /template/ ToggleButton#PART_toggle"> <Style Selector="Expander /template/ ToggleButton#PART_toggle">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/> <Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style> </Style>
</Expander.Styles> </Expander.Styles>
<Expander.Header> <Expander.Header>
<Grid ColumnDefinitions="Auto,Auto,*,Auto"> <Grid ColumnDefinitions="Auto,Auto,*,Auto">
<ToggleSwitch <ToggleSwitch
Margin="2,0,0,2" Margin="2,0,0,2"
IsChecked="{Binding IsEnabled}"
VerticalContentAlignment="Center" VerticalContentAlignment="Center"
OnContent="" IsChecked="{Binding IsEnabled}"
OffContent=""/> OffContent=""
OnContent="" />
<TextBlock <TextBlock
Grid.Column="1" Grid.Column="1"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{Binding TitleExtra}" IsVisible="{Binding TitleExtra, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
IsVisible="{Binding TitleExtra, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/> Text="{Binding TitleExtra}" />
<TextBlock <TextBlock
Grid.Column="2" Grid.Column="2"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{Binding Title}"/> Text="{Binding Title}" />
<Button <!-- Delete button for StackEditableCard -->
IsVisible="{Binding IsEditEnabled}" <Button
Command="{Binding RemoveFromParentListCommand}" Grid.Column="3"
Padding="12,6"
HorizontalAlignment="Right"
Classes="transparent-red" Classes="transparent-red"
Grid.Column="3" Command="{Binding RemoveFromParentListCommand}"
Padding="10,4" IsVisible="{Binding IsEditEnabled}">
HorizontalAlignment="Right"> <fluentIcons:SymbolIcon FontSize="16" Symbol="Delete" />
<fluentIcons:SymbolIcon Symbol="Delete" FontSize="16" /> </Button>
<!-- Settings button -->
<Button
Grid.Column="3"
Padding="12,6"
HorizontalAlignment="Right"
Classes="transparent-full"
Command="{Binding SettingsCommand}"
IsVisible="{Binding IsSettingsEnabled}">
<fluentIcons:SymbolIcon FontSize="17" Symbol="Settings" />
</Button> </Button>
</Grid> </Grid>
</Expander.Header> </Expander.Header>
<Panel> <Panel>
<ItemsControl <ItemsControl VerticalAlignment="Top" ItemsSource="{Binding Cards}">
VerticalAlignment="Top"
ItemsSource="{Binding Cards}">
<ItemsControl.Styles> <ItemsControl.Styles>
<Style Selector="controls|Card"> <Style Selector="controls|Card">
<Setter Property="IsCardVisualsEnabled" Value="False"/> <Setter Property="IsCardVisualsEnabled" Value="False" />
</Style> </Style>
</ItemsControl.Styles> </ItemsControl.Styles>
<ItemsControl.DataTemplates> <ItemsControl.DataTemplates>
<local:ViewLocator/> <local:ViewLocator />
</ItemsControl.DataTemplates> </ItemsControl.DataTemplates>
<ItemsControl.ItemsPanel> <ItemsControl.ItemsPanel>
<ItemsPanelTemplate> <ItemsPanelTemplate>
<StackPanel <StackPanel
x:Name="PART_ItemsPanel" x:Name="PART_ItemsPanel"
VerticalAlignment="Top" VerticalAlignment="Top"
Spacing="{TemplateBinding Spacing}" /> Spacing="{TemplateBinding Spacing}" />
@ -88,7 +100,7 @@
</ItemsControl> </ItemsControl>
</Panel> </Panel>
</Expander> </Expander>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>

17
StabilityMatrix.Avalonia/DesignData/DesignData.cs

@ -1,11 +1,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Net.Http; using System.Net.Http;
using System.Text; using System.Text;
using AvaloniaEdit.Utils; using AvaloniaEdit.Utils;
using CommunityToolkit.Mvvm.ComponentModel;
using DynamicData; using DynamicData;
using DynamicData.Binding; using DynamicData.Binding;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -631,7 +633,11 @@ The gallery images are often inpainted, but you will get something very similar
public static PropertyGridViewModel PropertyGridViewModel => public static PropertyGridViewModel PropertyGridViewModel =>
DialogFactory.Get<PropertyGridViewModel>(vm => DialogFactory.Get<PropertyGridViewModel>(vm =>
{ {
vm.SelectedObject = new MockPropertyGridObject(); vm.SelectedObject = new INotifyPropertyChanged[]
{
new MockPropertyGridObject(),
new MockPropertyGridObjectAlt()
};
vm.ExcludeCategories = ["Excluded Category"]; vm.ExcludeCategories = ["Excluded Category"];
}); });
@ -732,6 +738,15 @@ The gallery images are often inpainted, but you will get something very similar
vm.OnContainerIndexChanged(0); vm.OnContainerIndexChanged(0);
}); });
public static StackExpanderViewModel StackExpanderViewModel2 =>
DialogFactory.Get<StackExpanderViewModel>(vm =>
{
vm.Title = "Hires Fix";
vm.IsSettingsEnabled = true;
vm.AddCards(UpscalerCardViewModel, SamplerCardViewModel);
vm.OnContainerIndexChanged(1);
});
public static UpscalerCardViewModel UpscalerCardViewModel => DialogFactory.Get<UpscalerCardViewModel>(); public static UpscalerCardViewModel UpscalerCardViewModel => DialogFactory.Get<UpscalerCardViewModel>();
public static BatchSizeCardViewModel BatchSizeCardViewModel => DialogFactory.Get<BatchSizeCardViewModel>(); public static BatchSizeCardViewModel BatchSizeCardViewModel => DialogFactory.Get<BatchSizeCardViewModel>();

10
StabilityMatrix.Avalonia/DesignData/MockPropertyGridObject.cs

@ -42,3 +42,13 @@ public partial class MockPropertyGridObject : ObservableObject
[property: Category("Excluded Category")] [property: Category("Excluded Category")]
private string? stringExcludedCategoryProperty; private string? stringExcludedCategoryProperty;
} }
public partial class MockPropertyGridObjectAlt : ObservableObject
{
[ObservableProperty]
private int altIntProperty = 10;
[ObservableProperty]
[property: Category("Settings")]
private string? altStringProperty;
}

10
StabilityMatrix.Avalonia/ViewModels/Dialogs/PropertyGridViewModel.cs

@ -1,8 +1,11 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Linq;
using Avalonia.PropertyGrid.ViewModels; using Avalonia.PropertyGrid.ViewModels;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using OneOf; using OneOf;
using StabilityMatrix.Avalonia.DesignData;
using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.Views.Dialogs; using StabilityMatrix.Avalonia.Views.Dialogs;
using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Attributes;
@ -15,10 +18,11 @@ namespace StabilityMatrix.Avalonia.ViewModels.Dialogs;
public partial class PropertyGridViewModel : TaskDialogViewModelBase public partial class PropertyGridViewModel : TaskDialogViewModelBase
{ {
[ObservableProperty] [ObservableProperty]
[NotifyPropertyChangedFor(nameof(SelectedObjectSource))] [NotifyPropertyChangedFor(nameof(SelectedObjectItemsSource))]
private OneOf<INotifyPropertyChanged, IEnumerable<INotifyPropertyChanged>>? selectedObject; private OneOf<INotifyPropertyChanged, IEnumerable<INotifyPropertyChanged>>? selectedObject;
public object? SelectedObjectSource => SelectedObject?.Value; public IEnumerable<INotifyPropertyChanged>? SelectedObjectItemsSource =>
SelectedObject?.Match(single => [single], multiple => multiple);
[ObservableProperty] [ObservableProperty]
private PropertyGridShowStyle showStyle = PropertyGridShowStyle.Alphabetic; private PropertyGridShowStyle showStyle = PropertyGridShowStyle.Alphabetic;

49
StabilityMatrix.Avalonia/Views/Dialogs/PropertyGridDialog.axaml

@ -1,22 +1,33 @@
<controls:UserControlBase xmlns="https://github.com/avaloniaui" <controls:UserControlBase
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="StabilityMatrix.Avalonia.Views.Dialogs.PropertyGridDialog"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns="https://github.com/avaloniaui"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData" xmlns:componentModel="clr-namespace:System.ComponentModel;assembly=System.ObjectModel"
xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls"
xmlns:vmDialogs="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Dialogs" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:pg="clr-namespace:Avalonia.PropertyGrid.Controls;assembly=Avalonia.PropertyGrid" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DataContext="{x:Static mocks:DesignData.PropertyGridViewModel}" xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData"
x:DataType="vmDialogs:PropertyGridViewModel" xmlns:vmDialogs="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Dialogs"
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="450" d:DataContext="{x:Static mocks:DesignData.PropertyGridViewModel}"
x:Class="StabilityMatrix.Avalonia.Views.Dialogs.PropertyGridDialog"> d:DesignHeight="450"
d:DesignWidth="600"
x:DataType="vmDialogs:PropertyGridViewModel"
mc:Ignorable="d">
<Grid> <Grid>
<controls:BetterPropertyGrid <ItemsControl x:Name="MainItemsControl" ItemsSource="{Binding SelectedObjectItemsSource, Mode=OneTime}">
x:Name="MainPropertyGrid" <ItemsControl.ItemTemplate>
SelectedObject="{Binding SelectedObjectSource, Mode=OneTime}" <DataTemplate DataType="componentModel:INotifyPropertyChanged">
ShowStyle="{Binding ShowStyle}" <controls:BetterPropertyGrid
AllowQuickFilter="False" AllowFilter="False"
AllowFilter="False" AllowQuickFilter="False"
ShowTitle="False" /> SelectedObject="{Binding Mode=OneTime}"
IncludedCategories="{Binding $parent[ItemsControl].((vmDialogs:PropertyGridViewModel)DataContext).IncludeCategories, Mode=OneTime, FallbackValue=''}"
ExcludedCategories="{Binding $parent[ItemsControl].((vmDialogs:PropertyGridViewModel)DataContext).ExcludeCategories, Mode=OneTime, FallbackValue=''}"
ShowStyle="{Binding $parent[ItemsControl].((vmDialogs:PropertyGridViewModel)DataContext).ShowStyle, Mode=OneTime, FallbackValue=Alphabetic}"
ShowTitle="False" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid> </Grid>
</controls:UserControlBase> </controls:UserControlBase>

43
StabilityMatrix.Avalonia/Views/Dialogs/PropertyGridDialog.axaml.cs

@ -1,9 +1,4 @@
using Avalonia.Controls.Primitives; using StabilityMatrix.Avalonia.Controls;
using Avalonia.PropertyGrid.Controls;
using Avalonia.PropertyGrid.ViewModels;
using PropertyModels.ComponentModel;
using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Avalonia.ViewModels.Dialogs;
using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Attributes;
namespace StabilityMatrix.Avalonia.Views.Dialogs; namespace StabilityMatrix.Avalonia.Views.Dialogs;
@ -15,40 +10,4 @@ public partial class PropertyGridDialog : UserControlBase
{ {
InitializeComponent(); InitializeComponent();
} }
/// <inheritdoc />
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
var vm = DataContext as PropertyGridViewModel;
if (vm?.ExcludeCategories is { } excludeCategories)
{
MainPropertyGrid.FilterExcludeCategories(excludeCategories);
}
if (vm?.IncludeCategories is { } includeCategories)
{
MainPropertyGrid.FilterIncludeCategories(includeCategories);
}
}
internal class CustomFilter : IPropertyGridFilterContext
{
/// <inheritdoc />
public IFilterPattern? FilterPattern => null;
/// <inheritdoc />
public ICheckedMaskModel? FastFilterPattern => null;
/// <inheritdoc />
public PropertyVisibility PropagateVisibility(
IPropertyGridCellInfo info,
FilterCategory category = FilterCategory.Default
)
{
return PropertyVisibility.AlwaysVisible;
}
}
} }

Loading…
Cancel
Save