Merge pull request #432 from irihitech/breadcrumb
Fix BreadcrumbItem :last pseudo class for dynamic added items.
This commit is contained in:
16
Ursa.sln
16
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
|
||||
|
||||
@@ -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<BreadcrumbItem>().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))
|
||||
{
|
||||
|
||||
@@ -74,4 +74,9 @@ public class BreadcrumbItem: ContentControl
|
||||
Command?.Execute(CommandParameter);
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetPseudoClassLast(bool isLast)
|
||||
{
|
||||
PseudoClasses.Set(PC_Last, isLast);
|
||||
}
|
||||
}
|
||||
10
tests/HeadlessTest.Ursa/App.axaml
Normal file
10
tests/HeadlessTest.Ursa/App.axaml
Normal file
@@ -0,0 +1,10 @@
|
||||
<Application xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:semi="https://irihi.tech/semi"
|
||||
xmlns:u-semi="https://irihi.tech/ursa/themes/semi"
|
||||
x:Class="HeadlessTest.Ursa.App">
|
||||
<Application.Styles>
|
||||
<semi:SemiTheme />
|
||||
<u-semi:SemiTheme/>
|
||||
</Application.Styles>
|
||||
</Application>
|
||||
13
tests/HeadlessTest.Ursa/App.axaml.cs
Normal file
13
tests/HeadlessTest.Ursa/App.axaml.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
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<BreadcrumbItem>().FirstOrDefault();
|
||||
Assert.NotNull(firstItem);
|
||||
Assert.Contains(":last", firstItem.Classes);
|
||||
breadcrumb.Items.Add(item2);
|
||||
var lastItem = breadcrumb.GetLogicalChildren().OfType<BreadcrumbItem>().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<string>();
|
||||
breadcrumb.ItemsSource = items;
|
||||
items.Add("Item 1");
|
||||
var item1 = breadcrumb.GetLogicalChildren().OfType<BreadcrumbItem>().FirstOrDefault();
|
||||
Assert.NotNull(item1);
|
||||
Assert.Contains(":last", item1.Classes);
|
||||
items.Add("Item 2");
|
||||
var item2 = breadcrumb.GetLogicalChildren().OfType<BreadcrumbItem>().LastOrDefault();
|
||||
Assert.NotNull(item2);
|
||||
Assert.Contains(":last", item2.Classes);
|
||||
Assert.DoesNotContain(":last", item1.Classes);
|
||||
}
|
||||
|
||||
[AvaloniaFact]
|
||||
public void Bulk_Added_BreadcrumbItem_Should_Have_Correct_PseudoClasses()
|
||||
{
|
||||
var window = new Window();
|
||||
var breadcrumb = new Breadcrumb();
|
||||
window.Content = breadcrumb;
|
||||
window.Show();
|
||||
var items = new ObservableCollection<string>
|
||||
{
|
||||
"Item 1",
|
||||
"Item 2"
|
||||
};
|
||||
breadcrumb.ItemsSource = items;
|
||||
var item1 = breadcrumb.GetLogicalChildren().OfType<BreadcrumbItem>().FirstOrDefault();
|
||||
var item2 = breadcrumb.GetLogicalChildren().OfType<BreadcrumbItem>().LastOrDefault();
|
||||
Assert.NotNull(item1);
|
||||
Assert.NotNull(item2);
|
||||
Assert.Contains(":last", item2.Classes);
|
||||
Assert.DoesNotContain(":last", item1.Classes);
|
||||
}
|
||||
}
|
||||
30
tests/HeadlessTest.Ursa/HeadlessTest.Ursa.csproj
Normal file
30
tests/HeadlessTest.Ursa/HeadlessTest.Ursa.csproj
Normal file
@@ -0,0 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia.Headless.XUnit" Version="11.1.3" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
|
||||
<PackageReference Include="Semi.Avalonia" Version="11.1.0.4" />
|
||||
<PackageReference Include="xunit" Version="2.5.3"/>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Ursa\Ursa.csproj" />
|
||||
<ProjectReference Include="..\..\src\Ursa.Themes.Semi\Ursa.Themes.Semi.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
13
tests/HeadlessTest.Ursa/TestAppBuilder.cs
Normal file
13
tests/HeadlessTest.Ursa/TestAppBuilder.cs
Normal file
@@ -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<App>().UseHeadless(new AvaloniaHeadlessPlatformOptions());
|
||||
}
|
||||
27
tests/Test.Ursa/Test.Ursa.csproj
Normal file
27
tests/Test.Ursa/Test.Ursa.csproj
Normal file
@@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
|
||||
<PackageReference Include="xunit" Version="2.5.3"/>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Ursa\Ursa.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user