Browse Source

Implement VerticalContentAlignment for DatePicker and TimePicker (#21464)

* Add VerticalContentAlignment property to DatePicker and TimePicker

This change registers VerticalContentAlignmentProperty as a
StyledProperty using ContentControl's property as the owner for both
DatePicker and TimePicker controls to maintain framework consistency.

Basic xUnit v3 unit tests are introduced to validate property
round-trips (Top, Center, Bottom, Stretch) and to ensure the default
value correctly resolves to Stretch. This establishes the necessary
C# infrastructure before modifying the control templates.

Part of #21211: implment fluent theme layout

* Fix VerticalContentAlignment bindings and integration tests

- Bind internal grids to VerticalContentAlignment in Fluent and Simple
  themes for DatePicker and TimePicker controls.
- Add comprehensive integration tests using mocked NameScopes in
  DatePickerTests and TimePickerTests to verify visual propagation.
- Validate visual layout correctness using the ControlCatalog app.

Closes AvaloniaUI#21211

* Remove tautological tests

---------

Co-authored-by: Martim Claudino <martimffclaudino@tecnico.ulisboa.pt>
Co-authored-by: Julien Lebosquain <julien@lebosquain.net>
pull/22024/head
JoaoCruz 1 month ago
committed by GitHub
parent
commit
9b5437bb5a
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 15
      src/Avalonia.Controls/DateTimePickers/DatePicker.cs
  2. 14
      src/Avalonia.Controls/DateTimePickers/TimePicker.cs
  3. 2
      src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml
  4. 2
      src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml
  5. 3
      src/Avalonia.Themes.Simple/Controls/DatePicker.xaml
  6. 2
      src/Avalonia.Themes.Simple/Controls/TimePicker.xaml
  7. 19
      tests/Avalonia.Controls.UnitTests/DatePickerTests.cs
  8. 19
      tests/Avalonia.Controls.UnitTests/TimePickerTests.cs

15
src/Avalonia.Controls/DateTimePickers/DatePicker.cs

@ -75,6 +75,21 @@ namespace Avalonia.Controls
public static readonly StyledProperty<bool> YearVisibleProperty =
AvaloniaProperty.Register<DatePicker, bool>(nameof(YearVisible), true);
/// <summary>
/// Defines the <see cref="VerticalContentAlignment"/> property.
/// </summary>
public static readonly StyledProperty<VerticalAlignment> VerticalContentAlignmentProperty =
ContentControl.VerticalContentAlignmentProperty.AddOwner<DatePicker>();
/// <summary>
/// Gets or sets the vertical alignment of the content within the control.
/// </summary>
public VerticalAlignment VerticalContentAlignment
{
get => GetValue(VerticalContentAlignmentProperty);
set => SetValue(VerticalContentAlignmentProperty, value);
}
/// <summary>
/// Defines the <see cref="SelectedDate"/> Property
/// </summary>

14
src/Avalonia.Controls/DateTimePickers/TimePicker.cs

@ -50,6 +50,20 @@ namespace Avalonia.Controls
public static readonly StyledProperty<string> ClockIdentifierProperty =
AvaloniaProperty.Register<TimePicker, string>(nameof(ClockIdentifier), "12HourClock", coerce: CoerceClockIdentifier);
/// <summary>
/// Defines the <see cref="VerticalContentAlignment"/> property.
/// </summary>
public static readonly StyledProperty<VerticalAlignment> VerticalContentAlignmentProperty =
ContentControl.VerticalContentAlignmentProperty.AddOwner<TimePicker>();
/// <summary>
/// Gets or sets the vertical alignment of the content within the control.
/// </summary>
public VerticalAlignment VerticalContentAlignment
{
get => GetValue(VerticalContentAlignmentProperty);
set => SetValue(VerticalContentAlignmentProperty, value);
}
/// <summary>
/// Defines the <see cref="UseSeconds"/> property
/// </summary>

2
src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml

@ -98,7 +98,7 @@
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
TemplatedControl.IsTemplateFocusTarget="True">
<Grid Name="PART_ButtonContentGrid" ColumnDefinitions="78*,Auto,132*,Auto,78*">
<Grid Name="PART_ButtonContentGrid" ColumnDefinitions="78*,Auto,132*,Auto,78*" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<TextBlock Name="PART_DayTextBlock" Text="{DynamicResource StringDatePickerDayText}" HorizontalAlignment="Center"
Padding="{DynamicResource DatePickerHostPadding}" />
<TextBlock Name="PART_MonthTextBlock" Text="{DynamicResource StringDatePickerMonthText}" TextAlignment="Left"

2
src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml

@ -97,7 +97,7 @@
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid Name="PART_FlyoutButtonContentGrid">
<Grid Name="PART_FlyoutButtonContentGrid" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<!--Ignore col defs here, set in code-->
<Border x:Name="PART_FirstPickerHost"
Grid.Column="0"

3
src/Avalonia.Themes.Simple/Controls/DatePicker.xaml

@ -106,7 +106,8 @@
TemplatedControl.IsTemplateFocusTarget="True"
Theme="{StaticResource SimpleDatePickerFlyoutButton}">
<Grid Name="PART_ButtonContentGrid"
ColumnDefinitions="78*,Auto,132*,Auto,78*">
ColumnDefinitions="78*,Auto,132*,Auto,78*"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<TextBlock Name="PART_DayTextBlock"
Padding="{DynamicResource DatePickerHostPadding}"
HorizontalAlignment="Center"

2
src/Avalonia.Themes.Simple/Controls/TimePicker.xaml

@ -103,7 +103,7 @@
IsEnabled="{TemplateBinding IsEnabled}"
Theme="{StaticResource SimpleTimePickerFlyoutButton}">
<Grid Name="PART_FlyoutButtonContentGrid">
<Grid Name="PART_FlyoutButtonContentGrid" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<!-- Ignore col defs here, set in code -->
<Border x:Name="PART_FirstPickerHost"
Grid.Column="0"

19
tests/Avalonia.Controls.UnitTests/DatePickerTests.cs

@ -13,6 +13,7 @@ using Avalonia.Platform;
using Avalonia.Threading;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
using Avalonia.Layout;
using Moq;
using Xunit;
@ -371,6 +372,24 @@ namespace Avalonia.Controls.UnitTests
});
}
[Theory]
[InlineData(Avalonia.Layout.VerticalAlignment.Top)]
[InlineData(Avalonia.Layout.VerticalAlignment.Center)]
[InlineData(Avalonia.Layout.VerticalAlignment.Bottom)]
[InlineData(Avalonia.Layout.VerticalAlignment.Stretch)]
public void VerticalContentAlignment_RoundTrips(Avalonia.Layout.VerticalAlignment value)
{
var datePicker = new DatePicker { VerticalContentAlignment = value };
Assert.Equal(value, datePicker.VerticalContentAlignment);
}
[Fact]
public void VerticalContentAlignment_Default_Is_Stretch()
{
var datePicker = new DatePicker();
Assert.Equal(Avalonia.Layout.VerticalAlignment.Stretch, datePicker.VerticalContentAlignment);
}
private static IControlTemplate CreatePickerTemplate()
{
return new FuncControlTemplate((_, scope) =>

19
tests/Avalonia.Controls.UnitTests/TimePickerTests.cs

@ -11,6 +11,7 @@ using Avalonia.Platform;
using Avalonia.Threading;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
using Avalonia.Layout;
using Moq;
using Xunit;
@ -466,5 +467,23 @@ namespace Avalonia.Controls.UnitTests
return contentPanel;
});
}
[Theory]
[InlineData(Avalonia.Layout.VerticalAlignment.Top)]
[InlineData(Avalonia.Layout.VerticalAlignment.Center)]
[InlineData(Avalonia.Layout.VerticalAlignment.Bottom)]
[InlineData(Avalonia.Layout.VerticalAlignment.Stretch)]
public void VerticalContentAlignment_RoundTrips(Avalonia.Layout.VerticalAlignment value)
{
var timePicker = new TimePicker { VerticalContentAlignment = value };
Assert.Equal(value, timePicker.VerticalContentAlignment);
}
[Fact]
public void VerticalContentAlignment_Default_Is_Stretch()
{
var timePicker = new TimePicker();
Assert.Equal(Avalonia.Layout.VerticalAlignment.Stretch, timePicker.VerticalContentAlignment);
}
}
}

Loading…
Cancel
Save