Merge pull request #465 from irihitech/issue-422

New Dialog/Drawer/MessageBox option: StyleClass
This commit is contained in:
Dong Bin
2024-11-11 23:46:53 +08:00
committed by GitHub
26 changed files with 486 additions and 215 deletions

23
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,23 @@
name: Test
on:
push:
branches: [ "action/publish" ]
pull_request:
branches: [ "main" ]
jobs:
windows:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4.1.1
- name: Ursa Headless Test
run: dotnet test ./tests/HeadlessTest.Ursa
ubuntu:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4.1.1
- name: Ursa Headless Test
run: dotnet test ./tests/HeadlessTest.Ursa

View File

@@ -3,9 +3,18 @@
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:semi="https://irihi.tech/semi" xmlns:semi="https://irihi.tech/semi"
xmlns:u-semi="https://irihi.tech/ursa/themes/semi"> xmlns:u-semi="https://irihi.tech/ursa/themes/semi"
xmlns:u="https://irihi.tech/ursa"
xmlns:helpers="clr-namespace:Irihi.Avalonia.Shared.Helpers;assembly=Irihi.Avalonia.Shared">
<Application.Styles> <Application.Styles>
<semi:SemiTheme Locale="zh-CN" /> <semi:SemiTheme Locale="zh-CN" />
<u-semi:SemiTheme Locale="zh-CN" /> <u-semi:SemiTheme Locale="zh-CN" />
<!--This style is created to demonstrate Dialog StyleClass feature. This style is applied to Dialog Window-->
<Style Selector="u|DefaultDialogWindow.Custom">
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="Content" Value="CUSTOM"/>
<Setter Property="helpers:ClassHelper.Classes" Value="Warning"></Setter>
</Style>
</Style>
</Application.Styles> </Application.Styles>
</Application> </Application>

View File

@@ -51,6 +51,21 @@
IsThreeState="True" /> IsThreeState="True" />
<CheckBox u:FormItem.Label="CanDragMove" IsChecked="{Binding CanDragMove}" /> <CheckBox u:FormItem.Label="CanDragMove" IsChecked="{Binding CanDragMove}" />
<CheckBox u:FormItem.Label="CanResize" IsChecked="{Binding CanResize}" /> <CheckBox u:FormItem.Label="CanResize" IsChecked="{Binding CanResize}" />
<u:FormItem>
<u:FormItem.Label>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Style Class" />
<PathIcon
Width="12"
Height="12"
VerticalAlignment="Center"
TextElement.FontWeight="Normal"
Data="{DynamicResource DialogQuestionIconGlyph}"
ToolTip.Tip="Pass a Style Class to the created Dialog. In this example, if you set StyleClass as 'Custom', You will get Special Style for OK Button. These styles usually are defined in the root of your App/Window" />
</StackPanel>
</u:FormItem.Label>
<TextBox HorizontalAlignment="Stretch" Text="{Binding StyleClass}" />
</u:FormItem>
<Button <Button
HorizontalAlignment="Left" HorizontalAlignment="Left"
u:FormItem.NoLabel="True" u:FormItem.NoLabel="True"
@@ -128,6 +143,21 @@
IsChecked="{Binding IsLocal}" IsChecked="{Binding IsLocal}"
OffContent="Global" OffContent="Global"
OnContent="Local" /> OnContent="Local" />
<u:FormItem>
<u:FormItem.Label>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Style Class" />
<PathIcon
Width="12"
Height="12"
VerticalAlignment="Center"
TextElement.FontWeight="Normal"
Data="{DynamicResource DialogQuestionIconGlyph}"
ToolTip.Tip="Pass a Style Class to the created Dialog. In this example, if you set StyleClass as 'Custom', You will get Special Style for OK Button. These styles usually are defined in the root of your App/Window" />
</StackPanel>
</u:FormItem.Label>
<TextBox HorizontalAlignment="Stretch" Text="{Binding StyleClass}" />
</u:FormItem>
<Button <Button
HorizontalAlignment="Left" HorizontalAlignment="Left"
u:FormItem.NoLabel="True" u:FormItem.NoLabel="True"

View File

@@ -33,6 +33,7 @@ public partial class DefaultWindowDialogDemoViewModel: ObservableObject
[ObservableProperty] private bool? _isCloseButtonVisible; [ObservableProperty] private bool? _isCloseButtonVisible;
[ObservableProperty] private bool _canDragMove; [ObservableProperty] private bool _canDragMove;
[ObservableProperty] private bool _canResize; [ObservableProperty] private bool _canResize;
[ObservableProperty] private string? _styleClass;
public ICommand ShowDialogCommand { get; } public ICommand ShowDialogCommand { get; }
@@ -57,6 +58,7 @@ public partial class DefaultWindowDialogDemoViewModel: ObservableObject
StartupLocation = Location, StartupLocation = Location,
CanDragMove = CanDragMove, CanDragMove = CanDragMove,
CanResize = CanResize, CanResize = CanResize,
StyleClass = StyleClass,
}; };
if (X.HasValue && Y.HasValue) if (X.HasValue && Y.HasValue)
{ {
@@ -133,6 +135,7 @@ public partial class DefaultOverlayDialogDemoViewModel : ObservableObject
[ObservableProperty] private bool _isModal; [ObservableProperty] private bool _isModal;
[ObservableProperty] private bool _isLocal; [ObservableProperty] private bool _isLocal;
[ObservableProperty] private bool _canResize; [ObservableProperty] private bool _canResize;
[ObservableProperty] private string? _styleClass;
public ICommand ShowDialogCommand { get; } public ICommand ShowDialogCommand { get; }
@@ -163,6 +166,7 @@ public partial class DefaultOverlayDialogDemoViewModel : ObservableObject
CanDragMove = CanDragMove, CanDragMove = CanDragMove,
IsCloseButtonVisible = IsCloseButtonVisible, IsCloseButtonVisible = IsCloseButtonVisible,
CanResize = CanResize, CanResize = CanResize,
StyleClass = StyleClass,
}; };
string? dialogHostId = IsLocal ? DialogDemoViewModel.LocalHost : null; string? dialogHostId = IsLocal ? DialogDemoViewModel.LocalHost : null;
if (IsModal) if (IsModal)

View File

@@ -3,21 +3,31 @@
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:helpers="clr-namespace:Irihi.Avalonia.Shared.Helpers;assembly=Irihi.Avalonia.Shared"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:Ursa.Demo.Views"
xmlns:u="https://irihi.tech/ursa" xmlns:u="https://irihi.tech/ursa"
xmlns:viewModels="clr-namespace:Ursa.Demo.ViewModels" xmlns:viewModels="clr-namespace:Ursa.Demo.ViewModels"
xmlns:views="clr-namespace:Ursa.Demo.Views"
Title="Ursa.Demo" Title="Ursa.Demo"
d:DesignHeight="450" d:DesignHeight="450"
d:DesignWidth="800" d:DesignWidth="800"
x:CompileBindings="True" x:CompileBindings="True"
IsFullScreenButtonVisible="{OnPlatform True, macOS=False}"
IsManagedResizerVisible="{OnPlatform False, Linux=True}"
x:DataType="viewModels:MainWindowViewModel" x:DataType="viewModels:MainWindowViewModel"
Icon="/Assets/Ursa.ico" Icon="/Assets/Ursa.ico"
IsFullScreenButtonVisible="{OnPlatform True, macOS=False}"
IsManagedResizerVisible="{OnPlatform False, Linux=True}"
mc:Ignorable="d"> mc:Ignorable="d">
<u:UrsaWindow.RightContent> <u:UrsaWindow.RightContent>
<views:TitleBarRightContent/> <views:TitleBarRightContent />
</u:UrsaWindow.RightContent> </u:UrsaWindow.RightContent>
<u:UrsaWindow.Styles>
<!--This style is created to demonstrate Dialog StyleClass feature. This style is applied to dialogs in MainWindow OverlayDialogHost -->
<Style Selector="u|DefaultDialogControl.Custom">
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="Content" Value="CUSTOM" />
<Setter Property="helpers:ClassHelper.Classes" Value="Warning" />
</Style>
</Style>
</u:UrsaWindow.Styles>
<views:MainView /> <views:MainView />
</u:UrsaWindow> </u:UrsaWindow>

View File

@@ -1,69 +0,0 @@
using System.Collections.Specialized;
using Avalonia;
using Avalonia.Collections;
namespace Ursa.Themes.Semi;
internal class ClassHelper : AvaloniaObject
{
public static readonly AttachedProperty<string> ClassesProperty =
AvaloniaProperty.RegisterAttached<ClassHelper, StyledElement, string>("Classes");
public static readonly AttachedProperty<StyledElement> ClassSourceProperty =
AvaloniaProperty.RegisterAttached<ClassHelper, StyledElement, StyledElement>("ClassSource");
static ClassHelper()
{
ClassesProperty.Changed.AddClassHandler<StyledElement>(OnClassesChanged);
ClassSourceProperty.Changed.AddClassHandler<StyledElement>(OnClassSourceChanged);
}
private static void OnClassSourceChanged(StyledElement arg1, AvaloniaPropertyChangedEventArgs arg2)
{
if (arg2.NewValue is StyledElement styledElement)
{
arg1.Classes.Clear();
var nonPseudoClasses = styledElement.Classes.Where(c => !c.StartsWith(":"));
arg1.Classes.AddRange(nonPseudoClasses);
styledElement.Classes.WeakSubscribe((o, e) => OnSourceClassesChanged(o, e, arg1));
}
}
private static void OnSourceClassesChanged(object sender, NotifyCollectionChangedEventArgs e, StyledElement target)
{
if (sender is AvaloniaList<string> classes)
{
target.Classes.Clear();
var nonPseudoClasses = classes.Where(c => !c.StartsWith(":"));
target.Classes.AddRange(nonPseudoClasses);
}
}
public static void SetClasses(AvaloniaObject obj, string value)
{
obj.SetValue(ClassesProperty, value);
}
public static string GetClasses(AvaloniaObject obj)
{
return obj.GetValue(ClassesProperty);
}
private static void OnClassesChanged(StyledElement sender, AvaloniaPropertyChangedEventArgs value)
{
var classes = value.GetNewValue<string?>();
if (classes is null) return;
sender.Classes.Clear();
sender.Classes.Add(classes);
}
public static void SetClassSource(StyledElement obj, StyledElement value)
{
obj.SetValue(ClassSourceProperty, value);
}
public static StyledElement GetClassSource(StyledElement obj)
{
return obj.GetValue(ClassSourceProperty);
}
}

View File

@@ -2,7 +2,7 @@
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:u="https://irihi.tech/ursa" xmlns:u="https://irihi.tech/ursa"
xmlns:usemi="https://irihi.tech/ursa/themes/semi"> xmlns:helpers="clr-namespace:Irihi.Avalonia.Shared.Helpers;assembly=Irihi.Avalonia.Shared">
<!-- Add Resources Here --> <!-- Add Resources Here -->
<ControlTheme x:Key="{x:Type u:AutoCompleteBox}" TargetType="u:AutoCompleteBox"> <ControlTheme x:Key="{x:Type u:AutoCompleteBox}" TargetType="u:AutoCompleteBox">
<Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" />
@@ -15,7 +15,7 @@
Name="PART_TextBox" Name="PART_TextBox"
MinHeight="{TemplateBinding MinHeight}" MinHeight="{TemplateBinding MinHeight}"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
usemi:ClassHelper.ClassSource="{TemplateBinding}" helpers:ClassHelper.ClassSource="{TemplateBinding}"
DataValidationErrors.Errors="{TemplateBinding (DataValidationErrors.Errors)}" DataValidationErrors.Errors="{TemplateBinding (DataValidationErrors.Errors)}"
InnerLeftContent="{TemplateBinding InnerLeftContent}" InnerLeftContent="{TemplateBinding InnerLeftContent}"
InnerRightContent="{TemplateBinding InnerRightContent}" InnerRightContent="{TemplateBinding InnerRightContent}"

View File

@@ -1,8 +1,8 @@
<ResourceDictionary <ResourceDictionary
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:theme="clr-namespace:Ursa.Themes.Semi" xmlns:u="https://irihi.tech/ursa"
xmlns:u="https://irihi.tech/ursa"> xmlns:helpers="clr-namespace:Irihi.Avalonia.Shared.Helpers;assembly=Irihi.Avalonia.Shared">
<ControlTheme x:Key="{x:Type u:OverlayDialogHost}" TargetType="u:OverlayDialogHost"> <ControlTheme x:Key="{x:Type u:OverlayDialogHost}" TargetType="u:OverlayDialogHost">
<Setter Property="OverlayMaskBrush" Value="{DynamicResource OverlayDialogMaskBrush}" /> <Setter Property="OverlayMaskBrush" Value="{DynamicResource OverlayDialogMaskBrush}" />
@@ -207,35 +207,24 @@
DockPanel.Dock="Right" DockPanel.Dock="Right"
Theme="{DynamicResource OverlayCloseButton}" /> Theme="{DynamicResource OverlayCloseButton}" />
</Grid> </Grid>
<StackPanel <Grid
Grid.Row="2" Grid.Row="2"
Margin="24,0,24,24" Margin="24,0,24,24"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Orientation="Horizontal"> ColumnDefinitions="Auto, Auto, Auto, Auto">
<Button <Button
Name="{x:Static u:DefaultDialogControl.PART_CancelButton}" Name="{x:Static u:DefaultDialogControl.PART_CancelButton}"
Margin="8,0,0,0" Margin="8,0,0,0" />
Classes="Tertiary"
Content="{DynamicResource STRING_MENU_DIALOG_CANCEL}" />
<Button <Button
Name="{x:Static u:DefaultDialogControl.PART_NoButton}" Name="{x:Static u:DefaultDialogControl.PART_NoButton}"
Margin="8,0,0,0" Margin="8,0,0,0"/>
Classes="Danger"
Content="{DynamicResource STRING_MENU_DIALOG_NO}"
Theme="{DynamicResource SolidButton}" />
<Button <Button
Name="{x:Static u:DefaultDialogControl.PART_YesButton}" Name="{x:Static u:DefaultDialogControl.PART_YesButton}"
Margin="8,0,0,0" Margin="8,0,0,0"/>
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_YES}"
Theme="{DynamicResource SolidButton}" />
<Button <Button
Name="{x:Static u:DefaultDialogControl.PART_OKButton}" Name="{x:Static u:DefaultDialogControl.PART_OKButton}"
Margin="8,0,0,0" Margin="8,0,0,0"/>
Classes="Primary" </Grid>
Content="{DynamicResource STRING_MENU_DIALOG_OK}"
Theme="{DynamicResource SolidButton}" />
</StackPanel>
</Grid> </Grid>
</Border> </Border>
@@ -254,6 +243,29 @@
<Setter Property="Margin" Value="0" /> <Setter Property="Margin" Value="0" />
<Setter Property="Background" Value="{DynamicResource BorderCardBackground}" /> <Setter Property="Background" Value="{DynamicResource BorderCardBackground}" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="Grid.Column" Value="0"/>
<Setter Property="helpers:ClassHelper.Classes" Value="Tertiary"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_CANCEL}"/>
</Style>
<Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="Grid.Column" Value="1"></Setter>
<Setter Property="helpers:ClassHelper.Classes" Value="Danger"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_NO}"/>
<Setter Property="Theme" Value="{DynamicResource SolidButton}"/>
</Style>
<Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="Grid.Column" Value="2"></Setter>
<Setter Property="helpers:ClassHelper.Classes" Value="Primary"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_YES}"/>
<Setter Property="Theme" Value="{DynamicResource SolidButton}"/>
</Style>
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="Grid.Column" Value="3"></Setter>
<Setter Property="helpers:ClassHelper.Classes" Value="Primary"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_OK}"/>
<Setter Property="Theme" Value="{DynamicResource SolidButton}"/>
</Style>
<Style Selector="^[Mode=None]"> <Style Selector="^[Mode=None]">
<Style Selector="^ /template/ PathIcon#PART_Icon"> <Style Selector="^ /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="False" /> <Setter Property="IsVisible" Value="False" />
@@ -262,16 +274,16 @@
<Setter Property="Margin" Value="24 24 0 0" /> <Setter Property="Margin" Value="24 24 0 0" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_OKButton"> <Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Primary" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_YesButton"> <Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Primary" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_NoButton"> <Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" /> <Setter Property="helpers:ClassHelper.Classes" Value="Danger" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_CancelButton"> <Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Tertiary" />
</Style> </Style>
</Style> </Style>
<Style Selector="^[Mode=Info]"> <Style Selector="^[Mode=Info]">
@@ -281,16 +293,16 @@
<Setter Property="Foreground" Value="{DynamicResource SemiBlue6}" /> <Setter Property="Foreground" Value="{DynamicResource SemiBlue6}" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_OKButton"> <Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Primary" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_YesButton"> <Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Primary" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_NoButton"> <Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" /> <Setter Property="helpers:ClassHelper.Classes" Value="Danger" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_CancelButton"> <Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Tertiary" />
</Style> </Style>
</Style> </Style>
<Style Selector="^[Mode=Warning]"> <Style Selector="^[Mode=Warning]">
@@ -300,19 +312,19 @@
<Setter Property="Foreground" Value="{DynamicResource SemiOrange6}" /> <Setter Property="Foreground" Value="{DynamicResource SemiOrange6}" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_OKButton"> <Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Warning" /> <Setter Property="helpers:ClassHelper.Classes" Value="Warning" />
<Setter Property="Theme" Value="{DynamicResource SolidButton}" /> <Setter Property="Theme" Value="{DynamicResource SolidButton}" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_YesButton"> <Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Warning" /> <Setter Property="helpers:ClassHelper.Classes" Value="Warning" />
<Setter Property="Theme" Value="{DynamicResource SolidButton}" /> <Setter Property="Theme" Value="{DynamicResource SolidButton}" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_NoButton"> <Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" /> <Setter Property="helpers:ClassHelper.Classes" Value="Danger" />
<Setter Property="Theme" Value="{DynamicResource SolidButton}" /> <Setter Property="Theme" Value="{DynamicResource SolidButton}" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_CancelButton"> <Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Tertiary" />
</Style> </Style>
</Style> </Style>
<Style Selector="^[Mode=Error]"> <Style Selector="^[Mode=Error]">
@@ -322,16 +334,16 @@
<Setter Property="Foreground" Value="{DynamicResource SemiRed6}" /> <Setter Property="Foreground" Value="{DynamicResource SemiRed6}" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_OKButton"> <Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" /> <Setter Property="helpers:ClassHelper.Classes" Value="Danger" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_YesButton"> <Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" /> <Setter Property="helpers:ClassHelper.Classes" Value="Danger" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_NoButton"> <Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Tertiary" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_CancelButton"> <Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Tertiary" />
</Style> </Style>
</Style> </Style>
<Style Selector="^[Mode=Question]"> <Style Selector="^[Mode=Question]">
@@ -341,16 +353,16 @@
<Setter Property="Foreground" Value="{DynamicResource SemiBlue6}" /> <Setter Property="Foreground" Value="{DynamicResource SemiBlue6}" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_OKButton"> <Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Primary" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_YesButton"> <Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Primary" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_NoButton"> <Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" /> <Setter Property="helpers:ClassHelper.Classes" Value="Danger" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_CancelButton"> <Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Tertiary" />
</Style> </Style>
</Style> </Style>
<Style Selector="^[Mode=Success]"> <Style Selector="^[Mode=Success]">
@@ -360,16 +372,16 @@
<Setter Property="Foreground" Value="{DynamicResource SemiGreen6}" /> <Setter Property="Foreground" Value="{DynamicResource SemiGreen6}" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_OKButton"> <Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Success" /> <Setter Property="helpers:ClassHelper.Classes" Value="Success" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_YesButton"> <Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Success" /> <Setter Property="helpers:ClassHelper.Classes" Value="Success" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_NoButton"> <Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" /> <Setter Property="helpers:ClassHelper.Classes" Value="Danger" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_CancelButton"> <Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Tertiary" />
</Style> </Style>
</Style> </Style>
<Style Selector="^ /template/ Panel#PART_TitleArea"> <Style Selector="^ /template/ Panel#PART_TitleArea">
@@ -604,27 +616,16 @@
Orientation="Horizontal"> Orientation="Horizontal">
<Button <Button
Name="{x:Static u:DefaultDialogControl.PART_CancelButton}" Name="{x:Static u:DefaultDialogControl.PART_CancelButton}"
Margin="8,0,0,0" Margin="8,0,0,0" />
Classes="Tertiary"
Content="{DynamicResource STRING_MENU_DIALOG_CANCEL}" />
<Button <Button
Name="{x:Static u:DefaultDialogControl.PART_NoButton}" Name="{x:Static u:DefaultDialogControl.PART_NoButton}"
Margin="8,0,0,0" Margin="8,0,0,0" />
Classes="Danger"
Content="{DynamicResource STRING_MENU_DIALOG_NO}"
Theme="{DynamicResource SolidButton}" />
<Button <Button
Name="{x:Static u:DefaultDialogControl.PART_YesButton}" Name="{x:Static u:DefaultDialogControl.PART_YesButton}"
Margin="8,0,0,0" Margin="8,0,0,0" />
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_YES}"
Theme="{DynamicResource SolidButton}" />
<Button <Button
Name="{x:Static u:DefaultDialogControl.PART_OKButton}" Name="{x:Static u:DefaultDialogControl.PART_OKButton}"
Margin="8,0,0,0" Margin="8,0,0,0" />
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_OK}"
Theme="{DynamicResource SolidButton}" />
</StackPanel> </StackPanel>
</Grid> </Grid>
@@ -633,6 +634,29 @@
</Panel> </Panel>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
<Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="Grid.Column" Value="0"/>
<Setter Property="helpers:ClassHelper.Classes" Value="Tertiary"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_CANCEL}"/>
</Style>
<Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="Grid.Column" Value="1"></Setter>
<Setter Property="helpers:ClassHelper.Classes" Value="Danger"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_NO}"/>
<Setter Property="Theme" Value="{DynamicResource SolidButton}"/>
</Style>
<Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="Grid.Column" Value="2"></Setter>
<Setter Property="helpers:ClassHelper.Classes" Value="Primary"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_YES}"/>
<Setter Property="Theme" Value="{DynamicResource SolidButton}"/>
</Style>
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="Grid.Column" Value="3"></Setter>
<Setter Property="helpers:ClassHelper.Classes" Value="Primary"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_OK}"/>
<Setter Property="Theme" Value="{DynamicResource SolidButton}"/>
</Style>
<Style Selector="^[Mode=None]"> <Style Selector="^[Mode=None]">
<Style Selector="^ /template/ PathIcon#PART_Icon"> <Style Selector="^ /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="False" /> <Setter Property="IsVisible" Value="False" />
@@ -641,16 +665,16 @@
<Setter Property="Margin" Value="24 24 0 0" /> <Setter Property="Margin" Value="24 24 0 0" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_OKButton"> <Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Primary" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_YesButton"> <Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Primary" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_NoButton"> <Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" /> <Setter Property="helpers:ClassHelper.Classes" Value="Danger" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_CancelButton"> <Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Tertiary" />
</Style> </Style>
</Style> </Style>
<Style Selector="^[Mode=Info]"> <Style Selector="^[Mode=Info]">
@@ -660,16 +684,16 @@
<Setter Property="Foreground" Value="{DynamicResource SemiBlue6}" /> <Setter Property="Foreground" Value="{DynamicResource SemiBlue6}" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_OKButton"> <Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Primary" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_YesButton"> <Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Primary" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_NoButton"> <Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" /> <Setter Property="helpers:ClassHelper.Classes" Value="Danger" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_CancelButton"> <Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Tertiary" />
</Style> </Style>
</Style> </Style>
<Style Selector="^[Mode=Warning]"> <Style Selector="^[Mode=Warning]">
@@ -679,19 +703,19 @@
<Setter Property="Foreground" Value="{DynamicResource SemiOrange6}" /> <Setter Property="Foreground" Value="{DynamicResource SemiOrange6}" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_OKButton"> <Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Warning" /> <Setter Property="helpers:ClassHelper.Classes" Value="Warning" />
<Setter Property="Theme" Value="{DynamicResource SolidButton}" /> <Setter Property="Theme" Value="{DynamicResource SolidButton}" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_YesButton"> <Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Warning" /> <Setter Property="helpers:ClassHelper.Classes" Value="Warning" />
<Setter Property="Theme" Value="{DynamicResource SolidButton}" /> <Setter Property="Theme" Value="{DynamicResource SolidButton}" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_NoButton"> <Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" /> <Setter Property="helpers:ClassHelper.Classes" Value="Danger" />
<Setter Property="Theme" Value="{DynamicResource SolidButton}" /> <Setter Property="Theme" Value="{DynamicResource SolidButton}" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_CancelButton"> <Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Tertiary" />
</Style> </Style>
</Style> </Style>
<Style Selector="^[Mode=Error]"> <Style Selector="^[Mode=Error]">
@@ -701,16 +725,16 @@
<Setter Property="Foreground" Value="{DynamicResource SemiRed6}" /> <Setter Property="Foreground" Value="{DynamicResource SemiRed6}" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_OKButton"> <Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" /> <Setter Property="helpers:ClassHelper.Classes" Value="Danger" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_YesButton"> <Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" /> <Setter Property="helpers:ClassHelper.Classes" Value="Danger" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_NoButton"> <Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Tertiary" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_CancelButton"> <Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Tertiary" />
</Style> </Style>
</Style> </Style>
<Style Selector="^[Mode=Question]"> <Style Selector="^[Mode=Question]">
@@ -720,16 +744,16 @@
<Setter Property="Foreground" Value="{DynamicResource SemiBlue6}" /> <Setter Property="Foreground" Value="{DynamicResource SemiBlue6}" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_OKButton"> <Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Primary" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_YesButton"> <Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Primary" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_NoButton"> <Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" /> <Setter Property="helpers:ClassHelper.Classes" Value="Danger" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_CancelButton"> <Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Tertiary" />
</Style> </Style>
</Style> </Style>
<Style Selector="^[Mode=Success]"> <Style Selector="^[Mode=Success]">
@@ -739,16 +763,16 @@
<Setter Property="Foreground" Value="{DynamicResource SemiGreen6}" /> <Setter Property="Foreground" Value="{DynamicResource SemiGreen6}" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_OKButton"> <Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Success" /> <Setter Property="helpers:ClassHelper.Classes" Value="Success" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_YesButton"> <Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Success" /> <Setter Property="helpers:ClassHelper.Classes" Value="Success" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_NoButton"> <Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" /> <Setter Property="helpers:ClassHelper.Classes" Value="Danger" />
</Style> </Style>
<Style Selector="^ /template/ Button#PART_CancelButton"> <Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" /> <Setter Property="helpers:ClassHelper.Classes" Value="Tertiary" />
</Style> </Style>
</Style> </Style>
</ControlTheme> </ControlTheme>

View File

@@ -2,7 +2,8 @@
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:Ursa.Themes.Semi.Converters" xmlns:c="clr-namespace:Ursa.Themes.Semi.Converters"
xmlns:u="https://irihi.tech/ursa"> xmlns:u="https://irihi.tech/ursa"
xmlns:helpers="clr-namespace:Irihi.Avalonia.Shared.Helpers;assembly=Irihi.Avalonia.Shared">
<ControlTheme x:Key="{x:Type u:CustomDrawerControl}" TargetType="u:CustomDrawerControl"> <ControlTheme x:Key="{x:Type u:CustomDrawerControl}" TargetType="u:CustomDrawerControl">
<Setter Property="VerticalAlignment" Value="Stretch" /> <Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="HorizontalAlignment" Value="Stretch" /> <Setter Property="HorizontalAlignment" Value="Stretch" />
@@ -157,27 +158,16 @@
Orientation="Horizontal"> Orientation="Horizontal">
<Button <Button
Name="{x:Static u:DefaultDialogControl.PART_CancelButton}" Name="{x:Static u:DefaultDialogControl.PART_CancelButton}"
Margin="8,0,0,0" Margin="8,0,0,0" />
Classes="Tertiary"
Content="{DynamicResource STRING_MENU_DIALOG_CANCEL}" />
<Button <Button
Name="{x:Static u:DefaultDialogControl.PART_NoButton}" Name="{x:Static u:DefaultDialogControl.PART_NoButton}"
Margin="8,0,0,0" Margin="8,0,0,0" />
Classes="Danger"
Content="{DynamicResource STRING_MENU_DIALOG_NO}"
Theme="{DynamicResource SolidButton}" />
<Button <Button
Name="{x:Static u:DefaultDialogControl.PART_YesButton}" Name="{x:Static u:DefaultDialogControl.PART_YesButton}"
Margin="8,0,0,0" Margin="8,0,0,0" />
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_YES}"
Theme="{DynamicResource SolidButton}" />
<Button <Button
Name="{x:Static u:DefaultDialogControl.PART_OKButton}" Name="{x:Static u:DefaultDialogControl.PART_OKButton}"
Margin="8,0,0,0" Margin="8,0,0,0" />
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_OK}"
Theme="{DynamicResource SolidButton}" />
</StackPanel> </StackPanel>
</Grid> </Grid>
</Border> </Border>
@@ -186,6 +176,29 @@
</Panel> </Panel>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
<Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="Grid.Column" Value="0"/>
<Setter Property="helpers:ClassHelper.Classes" Value="Tertiary"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_CANCEL}"/>
</Style>
<Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="Grid.Column" Value="1"></Setter>
<Setter Property="helpers:ClassHelper.Classes" Value="Danger"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_NO}"/>
<Setter Property="Theme" Value="{DynamicResource SolidButton}"/>
</Style>
<Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="Grid.Column" Value="2"></Setter>
<Setter Property="helpers:ClassHelper.Classes" Value="Primary"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_YES}"/>
<Setter Property="Theme" Value="{DynamicResource SolidButton}"/>
</Style>
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="Grid.Column" Value="3"></Setter>
<Setter Property="helpers:ClassHelper.Classes" Value="Primary"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_OK}"/>
<Setter Property="Theme" Value="{DynamicResource SolidButton}"/>
</Style>
<Style Selector="^[Position=Right] /template/ Border#PART_Root"> <Style Selector="^[Position=Right] /template/ Border#PART_Root">
<Setter Property="Margin" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Padding, Converter={x:Static c:ThicknessTakeConverter.Left}}" /> <Setter Property="Margin" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Padding, Converter={x:Static c:ThicknessTakeConverter.Left}}" />
<Setter Property="CornerRadius" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=CornerRadius, Converter={x:Static c:CornerRadiusTakeConverter.Left}}" /> <Setter Property="CornerRadius" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=CornerRadius, Converter={x:Static c:CornerRadiusTakeConverter.Left}}" />

View File

@@ -2,7 +2,7 @@
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:u="https://irihi.tech/ursa" xmlns:u="https://irihi.tech/ursa"
xmlns:u-semi="https://irihi.tech/ursa/themes/semi"> xmlns:helpers="clr-namespace:Irihi.Avalonia.Shared.Helpers;assembly=Irihi.Avalonia.Shared">
<!-- Add Resources Here --> <!-- Add Resources Here -->
<ControlTheme x:Key="{x:Type u:EnumSelector}" TargetType="u:EnumSelector"> <ControlTheme x:Key="{x:Type u:EnumSelector}" TargetType="u:EnumSelector">
<Setter Property="HorizontalAlignment" Value="Left" /> <Setter Property="HorizontalAlignment" Value="Left" />
@@ -10,7 +10,7 @@
<ControlTemplate TargetType="u:EnumSelector"> <ControlTemplate TargetType="u:EnumSelector">
<ComboBox <ComboBox
Width="{TemplateBinding Width}" Width="{TemplateBinding Width}"
u-semi:ClassHelper.ClassSource="{TemplateBinding}" helpers:ClassHelper.ClassSource="{TemplateBinding}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}"
Name="PART_ComboBox" Name="PART_ComboBox"

View File

@@ -1,7 +1,8 @@
<ResourceDictionary <ResourceDictionary
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:u="https://irihi.tech/ursa"> xmlns:u="https://irihi.tech/ursa"
xmlns:helpers="clr-namespace:Irihi.Avalonia.Shared.Helpers;assembly=Irihi.Avalonia.Shared">
<!-- Add Resources Here --> <!-- Add Resources Here -->
<ControlTheme x:Key="{x:Type u:MessageBoxWindow}" TargetType="u:MessageBoxWindow"> <ControlTheme x:Key="{x:Type u:MessageBoxWindow}" TargetType="u:MessageBoxWindow">
<Setter Property="Title" Value="{x:Null}" /> <Setter Property="Title" Value="{x:Null}" />
@@ -90,33 +91,45 @@
Orientation="Horizontal"> Orientation="Horizontal">
<Button <Button
Name="{x:Static u:MessageBoxWindow.PART_CancelButton}" Name="{x:Static u:MessageBoxWindow.PART_CancelButton}"
Margin="8,0,0,0" Margin="8,0,0,0" />
Classes="Tertiary"
Content="{DynamicResource STRING_MENU_DIALOG_CANCEL}" />
<Button <Button
Name="{x:Static u:MessageBoxWindow.PART_NoButton}" Name="{x:Static u:MessageBoxWindow.PART_NoButton}"
Margin="8,0,0,0" Margin="8,0,0,0" />
Classes="Danger"
Content="{DynamicResource STRING_MENU_DIALOG_NO}"
Theme="{DynamicResource SolidButton}" />
<Button <Button
Name="{x:Static u:MessageBoxWindow.PART_YesButton}" Name="{x:Static u:MessageBoxWindow.PART_YesButton}"
Margin="8,0,0,0" Margin="8,0,0,0" />
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_YES}"
Theme="{DynamicResource SolidButton}" />
<Button <Button
Name="{x:Static u:MessageBoxWindow.PART_OKButton}" Name="{x:Static u:MessageBoxWindow.PART_OKButton}"
Margin="8,0,0,0" Margin="8,0,0,0" />
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_OK}"
Theme="{DynamicResource SolidButton}" />
</StackPanel> </StackPanel>
</Grid> </Grid>
</VisualLayerManager> </VisualLayerManager>
</Panel> </Panel>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
<Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="Grid.Column" Value="0"/>
<Setter Property="helpers:ClassHelper.Classes" Value="Tertiary"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_CANCEL}"/>
</Style>
<Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="Grid.Column" Value="1"></Setter>
<Setter Property="helpers:ClassHelper.Classes" Value="Danger"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_NO}"/>
<Setter Property="Theme" Value="{DynamicResource SolidButton}"/>
</Style>
<Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="Grid.Column" Value="2"></Setter>
<Setter Property="helpers:ClassHelper.Classes" Value="Primary"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_YES}"/>
<Setter Property="Theme" Value="{DynamicResource SolidButton}"/>
</Style>
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="Grid.Column" Value="3"></Setter>
<Setter Property="helpers:ClassHelper.Classes" Value="Primary"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_OK}"/>
<Setter Property="Theme" Value="{DynamicResource SolidButton}"/>
</Style>
<Style Selector="^[MessageIcon=None] /template/ PathIcon#PART_Icon"> <Style Selector="^[MessageIcon=None] /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="False" /> <Setter Property="IsVisible" Value="False" />
</Style> </Style>
@@ -224,27 +237,16 @@
Orientation="Horizontal"> Orientation="Horizontal">
<Button <Button
Name="{x:Static u:MessageBoxControl.PART_CancelButton}" Name="{x:Static u:MessageBoxControl.PART_CancelButton}"
Margin="8,0,0,0" Margin="8,0,0,0" />
Classes="Tertiary"
Content="{DynamicResource STRING_MENU_DIALOG_CANCEL}" />
<Button <Button
Name="{x:Static u:MessageBoxControl.PART_NoButton}" Name="{x:Static u:MessageBoxControl.PART_NoButton}"
Margin="8,0,0,0" Margin="8,0,0,0" />
Classes="Danger"
Content="{DynamicResource STRING_MENU_DIALOG_NO}"
Theme="{DynamicResource SolidButton}" />
<Button <Button
Name="{x:Static u:MessageBoxControl.PART_YesButton}" Name="{x:Static u:MessageBoxControl.PART_YesButton}"
Margin="8,0,0,0" Margin="8,0,0,0" />
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_YES}"
Theme="{DynamicResource SolidButton}" />
<Button <Button
Name="{x:Static u:MessageBoxControl.PART_OKButton}" Name="{x:Static u:MessageBoxControl.PART_OKButton}"
Margin="8,0,0,0" Margin="8,0,0,0" />
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_OK}"
Theme="{DynamicResource SolidButton}" />
</StackPanel> </StackPanel>
</Grid> </Grid>
</Border> </Border>
@@ -265,6 +267,29 @@
</MenuFlyout> </MenuFlyout>
</Setter> </Setter>
</Style> </Style>
<Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="Grid.Column" Value="0"/>
<Setter Property="helpers:ClassHelper.Classes" Value="Tertiary"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_CANCEL}"/>
</Style>
<Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="Grid.Column" Value="1"></Setter>
<Setter Property="helpers:ClassHelper.Classes" Value="Danger"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_NO}"/>
<Setter Property="Theme" Value="{DynamicResource SolidButton}"/>
</Style>
<Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="Grid.Column" Value="2"></Setter>
<Setter Property="helpers:ClassHelper.Classes" Value="Primary"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_YES}"/>
<Setter Property="Theme" Value="{DynamicResource SolidButton}"/>
</Style>
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="Grid.Column" Value="3"></Setter>
<Setter Property="helpers:ClassHelper.Classes" Value="Primary"/>
<Setter Property="Content" Value="{DynamicResource STRING_MENU_DIALOG_OK}"/>
<Setter Property="Theme" Value="{DynamicResource SolidButton}"/>
</Style>
<Style Selector="^[MessageIcon=None] /template/ PathIcon#PART_Icon"> <Style Selector="^[MessageIcon=None] /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="False" /> <Setter Property="IsVisible" Value="False" />
</Style> </Style>

View File

@@ -1,7 +1,8 @@
<Styles xmlns="https://github.com/avaloniaui" <Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:u="https://irihi.tech/ursa" xmlns:u="https://irihi.tech/ursa"
xmlns:theme="https://irihi.tech/ursa/themes/semi"> xmlns:theme="https://irihi.tech/ursa/themes/semi"
xmlns:helpers="clr-namespace:Irihi.Avalonia.Shared.Helpers;assembly=Irihi.Avalonia.Shared">
<Design.PreviewWith> <Design.PreviewWith>
<Border Padding="20"> <Border Padding="20">
<!-- Add Controls for Previewer Here --> <!-- Add Controls for Previewer Here -->
@@ -16,7 +17,7 @@
</Style> </Style>
<Style Selector="u|PinCode.Small"> <Style Selector="u|PinCode.Small">
<Style Selector="^ u|PinCodeItem"> <Style Selector="^ u|PinCodeItem">
<Setter Property="theme:ClassHelper.Classes" Value="Small"></Setter> <Setter Property="helpers:ClassHelper.Classes" Value="Small"></Setter>
<Style Selector="^:nth-last-child(n+2)"> <Style Selector="^:nth-last-child(n+2)">
<Setter Property="Margin" Value="0 0 6 0"></Setter> <Setter Property="Margin" Value="0 0 6 0"></Setter>
</Style> </Style>
@@ -24,7 +25,7 @@
</Style> </Style>
<Style Selector="u|PinCode.Large"> <Style Selector="u|PinCode.Large">
<Style Selector="^ u|PinCodeItem"> <Style Selector="^ u|PinCodeItem">
<Setter Property="theme:ClassHelper.Classes" Value="Large"></Setter> <Setter Property="helpers:ClassHelper.Classes" Value="Large"></Setter>
<Style Selector="^:nth-last-child(n+2)"> <Style Selector="^:nth-last-child(n+2)">
<Setter Property="Margin" Value="0 0 12 0"></Setter> <Setter Property="Margin" Value="0 0 12 0"></Setter>
</Style> </Style>

View File

@@ -214,6 +214,11 @@ public static class Dialog
else else
window.WindowStartupLocation = WindowStartupLocation.CenterOwner; window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
} }
if (!string.IsNullOrWhiteSpace(options.StyleClass))
{
var styles = options.StyleClass!.Split([' '], StringSplitOptions.RemoveEmptyEntries);
window.Classes.AddRange(styles);
}
} }
/// <summary> /// <summary>
@@ -240,5 +245,10 @@ public static class Dialog
else else
window.WindowStartupLocation = WindowStartupLocation.CenterOwner; window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
} }
if (!string.IsNullOrWhiteSpace(options.StyleClass))
{
var styles = options.StyleClass!.Split([' '], StringSplitOptions.RemoveEmptyEntries);
window.Classes.AddRange(styles);
}
} }
} }

View File

@@ -32,4 +32,5 @@ public class DialogOptions
public bool CanDragMove { get; set; } = true; public bool CanDragMove { get; set; } = true;
public bool CanResize { get; set; } public bool CanResize { get; set; }
public string? StyleClass { get; set; }
} }

View File

@@ -64,4 +64,6 @@ public class OverlayDialogOptions
public int? TopLevelHashCode { get; set; } public int? TopLevelHashCode { get; set; }
public bool CanResize { get; set; } public bool CanResize { get; set; }
public string? StyleClass { get; set; }
} }

View File

@@ -205,6 +205,11 @@ public static class OverlayDialog
control.IsCloseButtonVisible = options.IsCloseButtonVisible; control.IsCloseButtonVisible = options.IsCloseButtonVisible;
control.CanLightDismiss = options.CanLightDismiss; control.CanLightDismiss = options.CanLightDismiss;
control.CanResize = options.CanResize; control.CanResize = options.CanResize;
if (!string.IsNullOrWhiteSpace(options.StyleClass))
{
var styles = options.StyleClass!.Split([' '], StringSplitOptions.RemoveEmptyEntries);
control.Classes.AddRange(styles);
}
DialogControlBase.SetCanDragMove(control, options.CanDragMove); DialogControlBase.SetCanDragMove(control, options.CanDragMove);
} }
@@ -231,6 +236,11 @@ public static class OverlayDialog
control.CanLightDismiss = options.CanLightDismiss; control.CanLightDismiss = options.CanLightDismiss;
control.IsCloseButtonVisible = options.IsCloseButtonVisible; control.IsCloseButtonVisible = options.IsCloseButtonVisible;
control.CanResize = options.CanResize; control.CanResize = options.CanResize;
if (!string.IsNullOrWhiteSpace(options.StyleClass))
{
var styles = options.StyleClass!.Split([' '], StringSplitOptions.RemoveEmptyEntries);
control.Classes.AddRange(styles);
}
DialogControlBase.SetCanDragMove(control, options.CanDragMove); DialogControlBase.SetCanDragMove(control, options.CanDragMove);
} }

View File

@@ -217,6 +217,12 @@ public static class Drawer
if(options.MinHeight is not null) drawer.MinHeight = options.MinHeight.Value; if(options.MinHeight is not null) drawer.MinHeight = options.MinHeight.Value;
if(options.MaxHeight is not null) drawer.MaxHeight = options.MaxHeight.Value; if(options.MaxHeight is not null) drawer.MaxHeight = options.MaxHeight.Value;
} }
if (!string.IsNullOrWhiteSpace(options.StyleClass))
{
var styles = options.StyleClass!.Split([' '], StringSplitOptions.RemoveEmptyEntries);
drawer.Classes.AddRange(styles);
}
} }
private static void ConfigureDefaultDrawer(DefaultDrawerControl drawer, DrawerOptions? options) private static void ConfigureDefaultDrawer(DefaultDrawerControl drawer, DrawerOptions? options)
@@ -239,5 +245,10 @@ public static class Drawer
if(options.MinHeight is not null) drawer.MinHeight = options.MinHeight.Value; if(options.MinHeight is not null) drawer.MinHeight = options.MinHeight.Value;
if(options.MaxHeight is not null) drawer.MaxHeight = options.MaxHeight.Value; if(options.MaxHeight is not null) drawer.MaxHeight = options.MaxHeight.Value;
} }
if (!string.IsNullOrWhiteSpace(options.StyleClass))
{
var styles = options.StyleClass!.Split([' '], StringSplitOptions.RemoveEmptyEntries);
drawer.Classes.AddRange(styles);
}
} }
} }

View File

@@ -22,4 +22,6 @@ public class DrawerOptions
public int? TopLevelHashCode { get; set; } public int? TopLevelHashCode { get; set; }
public bool CanResize { get; set; } public bool CanResize { get; set; }
public string? StyleClass { get; set; }
} }

View File

@@ -11,7 +11,8 @@ public static class MessageBox
string message, string message,
string? title = null, string? title = null,
MessageBoxIcon icon = MessageBoxIcon.None, MessageBoxIcon icon = MessageBoxIcon.None,
MessageBoxButton button = MessageBoxButton.OK) MessageBoxButton button = MessageBoxButton.OK,
string? styleClass = null)
{ {
var messageWindow = new MessageBoxWindow(button) var messageWindow = new MessageBoxWindow(button)
{ {
@@ -19,6 +20,11 @@ public static class MessageBox
Title = title, Title = title,
MessageIcon = icon MessageIcon = icon
}; };
if (!string.IsNullOrWhiteSpace(styleClass))
{
var styles = styleClass!.Split([' '], StringSplitOptions.RemoveEmptyEntries);
messageWindow.Classes.AddRange(styles);
}
var lifetime = Application.Current?.ApplicationLifetime; var lifetime = Application.Current?.ApplicationLifetime;
if (lifetime is not IClassicDesktopStyleApplicationLifetime classLifetime) return MessageBoxResult.None; if (lifetime is not IClassicDesktopStyleApplicationLifetime classLifetime) return MessageBoxResult.None;
var main = classLifetime.MainWindow; var main = classLifetime.MainWindow;
@@ -37,7 +43,8 @@ public static class MessageBox
string message, string message,
string title, string title,
MessageBoxIcon icon = MessageBoxIcon.None, MessageBoxIcon icon = MessageBoxIcon.None,
MessageBoxButton button = MessageBoxButton.OK) MessageBoxButton button = MessageBoxButton.OK,
string? styleClass = null)
{ {
var messageWindow = new MessageBoxWindow(button) var messageWindow = new MessageBoxWindow(button)
{ {
@@ -45,6 +52,11 @@ public static class MessageBox
Title = title, Title = title,
MessageIcon = icon MessageIcon = icon
}; };
if (!string.IsNullOrWhiteSpace(styleClass))
{
var styles = styleClass!.Split([' '], StringSplitOptions.RemoveEmptyEntries);
messageWindow.Classes.AddRange(styles!);
}
var result = await messageWindow.ShowDialog<MessageBoxResult>(owner); var result = await messageWindow.ShowDialog<MessageBoxResult>(owner);
return result; return result;
} }
@@ -55,7 +67,8 @@ public static class MessageBox
string? hostId = null, string? hostId = null,
MessageBoxIcon icon = MessageBoxIcon.None, MessageBoxIcon icon = MessageBoxIcon.None,
MessageBoxButton button = MessageBoxButton.OK, MessageBoxButton button = MessageBoxButton.OK,
int? toplevelHashCode = null) int? toplevelHashCode = null,
string? styleClass = null)
{ {
var host = OverlayDialogManager.GetHost(hostId, toplevelHashCode); var host = OverlayDialogManager.GetHost(hostId, toplevelHashCode);
if (host is null) return MessageBoxResult.None; if (host is null) return MessageBoxResult.None;
@@ -67,6 +80,11 @@ public static class MessageBox
MessageIcon = icon, MessageIcon = icon,
[KeyboardNavigation.TabNavigationProperty] = KeyboardNavigationMode.Cycle [KeyboardNavigation.TabNavigationProperty] = KeyboardNavigationMode.Cycle
}; };
if (!string.IsNullOrWhiteSpace(styleClass))
{
var styles = styleClass!.Split([' '], StringSplitOptions.RemoveEmptyEntries);
messageControl.Classes.AddRange(styles!);
}
host.AddModalDialog(messageControl); host.AddModalDialog(messageControl);
var result = await messageControl.ShowAsync<MessageBoxResult>(); var result = await messageControl.ShowAsync<MessageBoxResult>();
return result; return result;

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Diagnostics;
namespace Ursa.Controls; namespace Ursa.Controls;
@@ -10,6 +11,7 @@ internal static class OverlayDialogManager
public static void RegisterHost(OverlayDialogHost host, string? id, int? hash) public static void RegisterHost(OverlayDialogHost host, string? id, int? hash)
{ {
Debug.WriteLine("Count: "+Hosts.Count);
Hosts.TryAdd(new HostKey(id, hash), host); Hosts.TryAdd(new HostKey(id, hash), host);
} }

View File

@@ -15,7 +15,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" Version="$(AvaloniaVersion)"/> <PackageReference Include="Avalonia" Version="$(AvaloniaVersion)"/>
<PackageReference Include="Irihi.Avalonia.Shared" Version="0.1.9" /> <PackageReference Include="Irihi.Avalonia.Shared" Version="0.2.1" />
<PackageReference Include="Irihi.Avalonia.Shared.Contracts" Version="0.2.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -0,0 +1,86 @@
using Avalonia.Controls;
using Avalonia.Headless.XUnit;
using Avalonia.Threading;
using Avalonia.VisualTree;
using Ursa.Controls;
using Xunit;
namespace HeadlessTest.Ursa.Controls.DialogTests.StyleClassTests;
public class StyleClassTests
{
[AvaloniaFact]
public void StyleClass_Changes_Button_Content()
{
var vm = new TestViewModel();
var ursaWindow = new TestWindow()
{
DataContext = vm,
};
ursaWindow.Show();
vm.InvokeDialog("Custom", ursaWindow.GetHashCode());
Dispatcher.UIThread.RunJobs();
var dialog = ursaWindow.GetVisualDescendants().OfType<DefaultDialogControl>().SingleOrDefault();
Assert.NotNull(dialog);
Assert.Contains("Custom", dialog.Classes);
var okButton = dialog.GetVisualDescendants().OfType<Button>().SingleOrDefault(a=>a.Name == DefaultDialogControl.PART_OKButton);
Assert.NotNull(okButton);
Assert.Equal("CUSTOM", okButton.Content);
var cancelButton = dialog.GetVisualDescendants().OfType<Button>().SingleOrDefault(a=>a.Name == DefaultDialogControl.PART_CancelButton);
Assert.NotNull(cancelButton);
Assert.Equal("取消", cancelButton.Content);
ursaWindow.Close();
Dispatcher.UIThread.RunJobs();
}
[AvaloniaFact]
public void StyleClass_Changes_Button_Content_With_Multiple_Classes()
{
var vm = new TestViewModel();
var ursaWindow = new TestWindow()
{
DataContext = vm,
};
ursaWindow.Show();
vm.InvokeDialog("Custom Custom2", ursaWindow.GetHashCode());
Dispatcher.UIThread.RunJobs();
var dialog = ursaWindow.GetVisualDescendants().OfType<DefaultDialogControl>().SingleOrDefault();
Assert.NotNull(dialog);
Assert.Contains("Custom", dialog.Classes);
Assert.Contains("Custom2", dialog.Classes);
var okButton = dialog.GetVisualDescendants().OfType<Button>().SingleOrDefault(a=>a.Name == DefaultDialogControl.PART_OKButton);
Assert.NotNull(okButton);
Assert.Equal("CUSTOM", okButton.Content);
Assert.Contains("Warning", okButton.Classes);
Assert.Contains("Small", okButton.Classes);
var cancelButton = dialog.GetVisualDescendants().OfType<Button>().SingleOrDefault(a=>a.Name == DefaultDialogControl.PART_CancelButton);
Assert.NotNull(cancelButton);
Assert.Equal("取消", cancelButton.Content);
ursaWindow.Close();
Dispatcher.UIThread.RunJobs();
}
[AvaloniaFact]
public void StyleClass_Changes_Button_Content_With_No_StyleClass()
{
var vm = new TestViewModel();
var ursaWindow = new TestWindow()
{
DataContext = vm,
};
ursaWindow.Show();
vm.InvokeDialog(null, ursaWindow.GetHashCode());
Dispatcher.UIThread.RunJobs();
var dialog = ursaWindow.GetVisualDescendants().OfType<DefaultDialogControl>().SingleOrDefault();
Assert.NotNull(dialog);
Assert.DoesNotContain("Custom", dialog.Classes);
var okButton = dialog.GetVisualDescendants().OfType<Button>().SingleOrDefault(a=>a.Name == DefaultDialogControl.PART_OKButton);
Assert.NotNull(okButton);
Assert.Equal("确认", okButton.Content);
var cancelButton = dialog.GetVisualDescendants().OfType<Button>().SingleOrDefault(a=>a.Name == DefaultDialogControl.PART_CancelButton);
Assert.NotNull(cancelButton);
Assert.Equal("取消", cancelButton.Content);
ursaWindow.Close();
Dispatcher.UIThread.RunJobs();
}
}

View File

@@ -0,0 +1,18 @@
using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using Ursa.Controls;
namespace HeadlessTest.Ursa.Controls.DialogTests.StyleClassTests;
public class TestViewModel: ObservableObject
{
public void InvokeDialog(string? classes, int? hash)
{
OverlayDialog.Show<TextBlock, string>("Hello World", options: new OverlayDialogOptions()
{
Buttons = DialogButton.OKCancel,
StyleClass = classes,
TopLevelHashCode = hash,
});
}
}

View File

@@ -0,0 +1,25 @@
<u:UrsaWindow xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:u="https://irihi.tech/ursa"
xmlns:helpers="clr-namespace:Irihi.Avalonia.Shared.Helpers;assembly=Irihi.Avalonia.Shared"
mc:Ignorable="d" d:DesignWidth="800"
d:DesignHeight="450"
x:Class="HeadlessTest.Ursa.Controls.DialogTests.StyleClassTests.TestWindow"
Title="TestWindow">
<u:UrsaWindow.Styles>
<Style Selector="u|DefaultDialogControl.Custom">
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="Content" Value="CUSTOM"/>
</Style>
</Style>
<Style Selector="u|DefaultDialogControl.Custom2">
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="helpers:ClassHelper.Classes" Value="Warning Small" />
</Style>
</Style>
</u:UrsaWindow.Styles>
Welcome to Avalonia!
</u:UrsaWindow>

View File

@@ -0,0 +1,14 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Ursa.Controls;
namespace HeadlessTest.Ursa.Controls.DialogTests.StyleClassTests;
public partial class TestWindow : UrsaWindow
{
public TestWindow()
{
InitializeComponent();
}
}

View File

@@ -11,6 +11,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia.Headless.XUnit" Version="11.1.3" /> <PackageReference Include="Avalonia.Headless.XUnit" Version="11.1.3" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.0" />
<PackageReference Include="coverlet.collector" Version="6.0.0"/> <PackageReference Include="coverlet.collector" Version="6.0.0"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
<PackageReference Include="Semi.Avalonia" Version="11.1.0.4" /> <PackageReference Include="Semi.Avalonia" Version="11.1.0.4" />