diff --git a/Ursa.sln b/Ursa.sln index 67d3ba1..7b48952 100644 --- a/Ursa.sln +++ b/Ursa.sln @@ -33,6 +33,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sandbox", "demo\Sandbox\San EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ursa.ReactiveUIExtension", "src\Ursa.ReactiveUIExtension\Ursa.ReactiveUIExtension.csproj", "{8DD57D6B-1C44-4E42-9541-8380DD17A3A4}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{49243F14-2D63-4361-BE31-BAF63951DE6F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test.Ursa", "tests\Test.Ursa\Test.Ursa.csproj", "{AC7B37DC-9B88-42C0-B176-0C274D14C68D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeadlessTest.Ursa", "tests\HeadlessTest.Ursa\HeadlessTest.Ursa.csproj", "{2D1C279E-7FFF-4630-92CC-CB2C33C3F80F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -83,6 +89,14 @@ Global {8DD57D6B-1C44-4E42-9541-8380DD17A3A4}.Debug|Any CPU.Build.0 = Debug|Any CPU {8DD57D6B-1C44-4E42-9541-8380DD17A3A4}.Release|Any CPU.ActiveCfg = Release|Any CPU {8DD57D6B-1C44-4E42-9541-8380DD17A3A4}.Release|Any CPU.Build.0 = Release|Any CPU + {AC7B37DC-9B88-42C0-B176-0C274D14C68D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AC7B37DC-9B88-42C0-B176-0C274D14C68D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AC7B37DC-9B88-42C0-B176-0C274D14C68D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AC7B37DC-9B88-42C0-B176-0C274D14C68D}.Release|Any CPU.Build.0 = Release|Any CPU + {2D1C279E-7FFF-4630-92CC-CB2C33C3F80F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2D1C279E-7FFF-4630-92CC-CB2C33C3F80F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2D1C279E-7FFF-4630-92CC-CB2C33C3F80F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2D1C279E-7FFF-4630-92CC-CB2C33C3F80F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -95,5 +109,7 @@ Global {D1942476-8473-4608-BB9F-5AC01083BBDA} = {A41BAF0D-DA61-4A63-889A-084BAD36FD66} {F99B3D07-4560-4B05-892C-0FF2757FEF2E} = {A41BAF0D-DA61-4A63-889A-084BAD36FD66} {1E94BAFD-867E-425F-8E12-7F416D523C94} = {A41BAF0D-DA61-4A63-889A-084BAD36FD66} + {AC7B37DC-9B88-42C0-B176-0C274D14C68D} = {49243F14-2D63-4361-BE31-BAF63951DE6F} + {2D1C279E-7FFF-4630-92CC-CB2C33C3F80F} = {49243F14-2D63-4361-BE31-BAF63951DE6F} EndGlobalSection EndGlobal diff --git a/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs b/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs index c020dfe..a95369c 100644 --- a/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs +++ b/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs @@ -1,3 +1,4 @@ +using System.Collections.Specialized; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Templates; @@ -83,9 +84,19 @@ public class Breadcrumb: ItemsControl return new BreadcrumbItem(); } + protected override void LogicalChildrenCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) + { + base.LogicalChildrenCollectionChanged(sender, e); + var breadcrumbItems = LogicalChildren.OfType().ToList(); + for (var i = 0; i < breadcrumbItems.Count; i++) + { + var breadcrumbItem = breadcrumbItems[i]; + breadcrumbItem.SetPseudoClassLast(i == breadcrumbItems.Count - 1); + } + } + protected override void PrepareContainerForItemOverride(Control container, object? item, int index) { - // base.PrepareContainerForItemOverride(container, item, index); if (container is not BreadcrumbItem breadcrumbItem) return; if (!breadcrumbItem.IsSet(BreadcrumbItem.SeparatorProperty)) { @@ -100,8 +111,6 @@ public class Breadcrumb: ItemsControl }); } - PseudolassesExtensions.Set(container.Classes, BreadcrumbItem.PC_Last, index == ItemCount - 1); - if (container == item) return; if(!breadcrumbItem.IsSet(ContentControl.ContentProperty)) { diff --git a/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs b/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs index ce87a47..4e93a35 100644 --- a/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs +++ b/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs @@ -74,4 +74,9 @@ public class BreadcrumbItem: ContentControl Command?.Execute(CommandParameter); } } + + internal void SetPseudoClassLast(bool isLast) + { + PseudoClasses.Set(PC_Last, isLast); + } } \ No newline at end of file diff --git a/tests/HeadlessTest.Ursa/App.axaml b/tests/HeadlessTest.Ursa/App.axaml new file mode 100644 index 0000000..a5c889d --- /dev/null +++ b/tests/HeadlessTest.Ursa/App.axaml @@ -0,0 +1,10 @@ + + + + + + diff --git a/tests/HeadlessTest.Ursa/App.axaml.cs b/tests/HeadlessTest.Ursa/App.axaml.cs new file mode 100644 index 0000000..eaed88e --- /dev/null +++ b/tests/HeadlessTest.Ursa/App.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace HeadlessTest.Ursa; + +public partial class App : Application +{ + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/tests/HeadlessTest.Ursa/Controls/BreadcrumbTests/BreadcrumbTests.cs b/tests/HeadlessTest.Ursa/Controls/BreadcrumbTests/BreadcrumbTests.cs new file mode 100644 index 0000000..9ca19c5 --- /dev/null +++ b/tests/HeadlessTest.Ursa/Controls/BreadcrumbTests/BreadcrumbTests.cs @@ -0,0 +1,66 @@ +using System.Collections.ObjectModel; +using Avalonia.Controls; +using Avalonia.Headless.XUnit; +using Avalonia.LogicalTree; +using Ursa.Controls; + +namespace HeadlessTest.Ursa.Controls; + +public class BreadcrumbTests +{ + [AvaloniaFact] + public void BreadcrumbItem_Should_Have_Correct_PseudoClasses() + { + var window = new Window(); + var breadcrumb = new Breadcrumb(); + window.Content = breadcrumb; + window.Show(); + var item1 = new BreadcrumbItem(); + var item2 = new BreadcrumbItem(); + breadcrumb.Items.Add(item1); + Assert.Contains(":last", item1.Classes); + breadcrumb.Items.Add(item2); + Assert.Contains(":last", item2.Classes); + Assert.DoesNotContain(":last", item1.Classes); + } + + [AvaloniaFact] + public void Generated_BreadcrumbItem_Should_Have_Correct_PseudoClasses() + { + var window = new Window(); + var breadcrumb = new Breadcrumb(); + window.Content = breadcrumb; + window.Show(); + var item1 = new TextBlock(); + var item2 = new TextBlock(); + breadcrumb.Items.Add(item1); + var firstItem = breadcrumb.GetLogicalChildren().OfType().FirstOrDefault(); + Assert.NotNull(firstItem); + Assert.Contains(":last", firstItem.Classes); + breadcrumb.Items.Add(item2); + var lastItem = breadcrumb.GetLogicalChildren().OfType().LastOrDefault(); + Assert.NotNull(lastItem); + Assert.Contains(":last", lastItem.Classes); + Assert.DoesNotContain(":last", firstItem.Classes); + } + + [AvaloniaFact] + public void BreadcrumbItem_FromItemsSource_Should_Have_Correct_PseudoClasses() + { + var window = new Window(); + var breadcrumb = new Breadcrumb(); + window.Content = breadcrumb; + window.Show(); + var items = new ObservableCollection(); + breadcrumb.ItemsSource = items; + items.Add("Item 1"); + var item1 = breadcrumb.GetLogicalChildren().OfType().FirstOrDefault(); + Assert.NotNull(item1); + Assert.Contains(":last", item1.Classes); + items.Add("Item 2"); + var item2 = breadcrumb.GetLogicalChildren().OfType().LastOrDefault(); + Assert.NotNull(item2); + Assert.Contains(":last", item2.Classes); + Assert.DoesNotContain(":last", item1.Classes); + } +} \ No newline at end of file diff --git a/tests/HeadlessTest.Ursa/HeadlessTest.Ursa.csproj b/tests/HeadlessTest.Ursa/HeadlessTest.Ursa.csproj new file mode 100644 index 0000000..edb294c --- /dev/null +++ b/tests/HeadlessTest.Ursa/HeadlessTest.Ursa.csproj @@ -0,0 +1,30 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/HeadlessTest.Ursa/TestAppBuilder.cs b/tests/HeadlessTest.Ursa/TestAppBuilder.cs new file mode 100644 index 0000000..e0cc73e --- /dev/null +++ b/tests/HeadlessTest.Ursa/TestAppBuilder.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Headless; +using HeadlessTest.Ursa; + +[assembly: AvaloniaTestApplication(typeof(TestAppBuilder))] + +namespace HeadlessTest.Ursa; + +public class TestAppBuilder +{ + public static AppBuilder BuildAvaloniaApp() => + AppBuilder.Configure().UseHeadless(new AvaloniaHeadlessPlatformOptions()); +} \ No newline at end of file diff --git a/tests/Test.Ursa/Test.Ursa.csproj b/tests/Test.Ursa/Test.Ursa.csproj new file mode 100644 index 0000000..ab4c0f3 --- /dev/null +++ b/tests/Test.Ursa/Test.Ursa.csproj @@ -0,0 +1,27 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + +