From 862aee2b02291cdeeebb24947b199771064d7997 Mon Sep 17 00:00:00 2001
From: Tom Edwards <109803929+TomEdwardsEnscape@users.noreply.github.com>
Date: Fri, 8 Aug 2025 10:52:18 +0200
Subject: [PATCH] Removed all nullability overrides from TimePickerPresenter
and DatePickerPresenter (#19241)
Fixed obscure cases where NullReferenceException could be thrown if a template hasn't been applied yet, or where it provides only some optional items
Replaced repeated string literals with shared const values
Relaxed template part requirements: RepeatButton to Button, Rectancle to Control
---
.../DateTimePickers/DatePickerPresenter.cs | 357 ++++++++--------
.../DateTimePickers/TimePickerPresenter.cs | 382 ++++++++++--------
2 files changed, 404 insertions(+), 335 deletions(-)
diff --git a/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs b/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs
index b745ed7779..bfe928309f 100644
--- a/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs
+++ b/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs
@@ -1,6 +1,5 @@
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
-using Avalonia.Controls.Shapes;
using Avalonia.Input;
using Avalonia.Interactivity;
using System;
@@ -13,23 +12,23 @@ namespace Avalonia.Controls
/// Defines the presenter used for selecting a date for a
///
///
- [TemplatePart("PART_AcceptButton", typeof(Button), IsRequired = true)]
- [TemplatePart("PART_DayDownButton", typeof(RepeatButton))]
- [TemplatePart("PART_DayHost", typeof(Panel), IsRequired = true)]
- [TemplatePart("PART_DaySelector", typeof(DateTimePickerPanel), IsRequired = true)]
- [TemplatePart("PART_DayUpButton", typeof(RepeatButton))]
- [TemplatePart("PART_DismissButton", typeof(Button))]
- [TemplatePart("PART_FirstSpacer", typeof(Rectangle))]
- [TemplatePart("PART_MonthDownButton", typeof(RepeatButton))]
- [TemplatePart("PART_MonthHost", typeof(Panel), IsRequired = true)]
- [TemplatePart("PART_MonthSelector", typeof(DateTimePickerPanel), IsRequired = true)]
- [TemplatePart("PART_MonthUpButton", typeof(RepeatButton))]
- [TemplatePart("PART_PickerContainer", typeof(Grid), IsRequired = true)]
- [TemplatePart("PART_SecondSpacer", typeof(Rectangle))]
- [TemplatePart("PART_YearDownButton", typeof(RepeatButton))]
- [TemplatePart("PART_YearHost", typeof(Panel), IsRequired = true)]
- [TemplatePart("PART_YearSelector", typeof(DateTimePickerPanel), IsRequired = true)]
- [TemplatePart("PART_YearUpButton", typeof(RepeatButton))]
+ [TemplatePart(TemplateItems.AcceptButtonName, typeof(Button), IsRequired = true)]
+ [TemplatePart(TemplateItems.DayDownButtonName, typeof(Button))]
+ [TemplatePart(TemplateItems.DayHostName, typeof(Panel), IsRequired = true)]
+ [TemplatePart(TemplateItems.DaySelectorName, typeof(DateTimePickerPanel), IsRequired = true)]
+ [TemplatePart(TemplateItems.DayUpButtonName, typeof(Button))]
+ [TemplatePart(TemplateItems.DismissButtonName, typeof(Button))]
+ [TemplatePart(TemplateItems.FirstSpacerName, typeof(Control))]
+ [TemplatePart(TemplateItems.MonthDownButtonName, typeof(Button))]
+ [TemplatePart(TemplateItems.MonthHostName, typeof(Panel), IsRequired = true)]
+ [TemplatePart(TemplateItems.MonthSelectorName, typeof(DateTimePickerPanel), IsRequired = true)]
+ [TemplatePart(TemplateItems.MonthUpButtonName, typeof(Button))]
+ [TemplatePart(TemplateItems.PickerContainerName, typeof(Grid), IsRequired = true)]
+ [TemplatePart(TemplateItems.SecondSpacerName, typeof(Control))]
+ [TemplatePart(TemplateItems.YearDownButtonName, typeof(Button))]
+ [TemplatePart(TemplateItems.YearHostName, typeof(Panel), IsRequired = true)]
+ [TemplatePart(TemplateItems.YearSelectorName, typeof(DateTimePickerPanel), IsRequired = true)]
+ [TemplatePart(TemplateItems.YearUpButtonName, typeof(Button))]
public class DatePickerPresenter : PickerPresenterBase
{
///
@@ -102,24 +101,61 @@ namespace Avalonia.Controls
public static readonly StyledProperty YearVisibleProperty =
DatePicker.YearVisibleProperty.AddOwner();
- // Template Items
- private Grid? _pickerContainer;
- private Button? _acceptButton;
- private Button? _dismissButton;
- private Rectangle? _spacer1;
- private Rectangle? _spacer2;
- private Panel? _monthHost;
- private Panel? _yearHost;
- private Panel? _dayHost;
- private DateTimePickerPanel? _monthSelector;
- private DateTimePickerPanel? _yearSelector;
- private DateTimePickerPanel? _daySelector;
- private Button? _monthUpButton;
- private Button? _dayUpButton;
- private Button? _yearUpButton;
- private Button? _monthDownButton;
- private Button? _dayDownButton;
- private Button? _yearDownButton;
+ private struct TemplateItems
+ {
+ public Grid _pickerContainer;
+ public const string PickerContainerName = "PART_PickerContainer";
+
+ public Button _acceptButton;
+ public const string AcceptButtonName = "PART_AcceptButton";
+
+ public Button? _dismissButton;
+ public const string DismissButtonName = "PART_DismissButton";
+
+ public Control? _firstSpacer;
+ public const string FirstSpacerName = "PART_FirstSpacer";
+
+ public Control? _secondSpacer;
+ public const string SecondSpacerName = "PART_SecondSpacer";
+
+ public Panel _monthHost;
+ public const string MonthHostName = "PART_MonthHost";
+
+ public Panel _yearHost;
+ public const string YearHostName = "PART_YearHost";
+
+ public Panel _dayHost;
+ public const string DayHostName = "PART_DayHost";
+
+ public DateTimePickerPanel _monthSelector;
+ public const string MonthSelectorName = "PART_MonthSelector";
+
+ public DateTimePickerPanel _yearSelector;
+ public const string YearSelectorName = "PART_YearSelector";
+
+ public DateTimePickerPanel _daySelector;
+ public const string DaySelectorName = "PART_DaySelector";
+
+ public Button? _monthUpButton;
+ public const string MonthUpButtonName = "PART_MonthUpButton";
+
+ public Button? _dayUpButton;
+ public const string DayUpButtonName = "PART_DayUpButton";
+
+ public Button? _yearUpButton;
+ public const string YearUpButtonName = "PART_YearUpButton";
+
+ public Button? _monthDownButton;
+ public const string MonthDownButtonName = "PART_MonthDownButton";
+
+ public Button? _dayDownButton;
+ public const string DayDownButtonName = "PART_DayDownButton";
+
+ public Button? _yearDownButton;
+ public const string YearDownButtonName = "PART_YearDownButton";
+ }
+
+ private TemplateItems? _templateItems;
private DateTimeOffset _syncDate;
@@ -235,69 +271,54 @@ namespace Avalonia.Controls
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
- // These are requirements, so throw if not found
- _pickerContainer = e.NameScope.Get("PART_PickerContainer");
- _monthHost = e.NameScope.Get("PART_MonthHost");
- _dayHost = e.NameScope.Get("PART_DayHost");
- _yearHost = e.NameScope.Get("PART_YearHost");
- _monthSelector = e.NameScope.Get("PART_MonthSelector");
- _monthSelector.SelectionChanged += OnMonthChanged;
-
- _daySelector = e.NameScope.Get("PART_DaySelector");
- _daySelector.SelectionChanged += OnDayChanged;
-
- _yearSelector = e.NameScope.Get("PART_YearSelector");
- _yearSelector.SelectionChanged += OnYearChanged;
-
- _acceptButton = e.NameScope.Get
- [TemplatePart("PART_AcceptButton", typeof(Button), IsRequired = true)]
- [TemplatePart("PART_DismissButton", typeof(Button))]
- [TemplatePart("PART_HourDownButton", typeof(RepeatButton))]
- [TemplatePart("PART_HourSelector", typeof(DateTimePickerPanel), IsRequired = true)]
- [TemplatePart("PART_HourUpButton", typeof(RepeatButton))]
- [TemplatePart("PART_MinuteDownButton", typeof(RepeatButton))]
- [TemplatePart("PART_MinuteSelector", typeof(DateTimePickerPanel), IsRequired = true)]
- [TemplatePart("PART_MinuteUpButton", typeof(RepeatButton))]
- [TemplatePart("PART_SecondDownButton", typeof(RepeatButton))]
- [TemplatePart("PART_SecondHost", typeof(Panel), IsRequired = true)]
- [TemplatePart("PART_SecondSelector", typeof(DateTimePickerPanel), IsRequired = true)]
- [TemplatePart("PART_SecondUpButton", typeof(RepeatButton))]
- [TemplatePart("PART_PeriodDownButton", typeof(RepeatButton))]
- [TemplatePart("PART_PeriodHost", typeof(Panel), IsRequired = true)]
- [TemplatePart("PART_PeriodSelector", typeof(DateTimePickerPanel), IsRequired = true)]
- [TemplatePart("PART_PeriodUpButton", typeof(RepeatButton))]
- [TemplatePart("PART_PickerContainer", typeof(Grid), IsRequired = true)]
- [TemplatePart("PART_SecondSpacer", typeof(Rectangle), IsRequired = true)]
- [TemplatePart("PART_ThirdSpacer", typeof(Rectangle), IsRequired = true)]
+ [TemplatePart(TemplateItems.AcceptButtonName, typeof(Button), IsRequired = true)]
+ [TemplatePart(TemplateItems.DismissButtonName, typeof(Button))]
+ [TemplatePart(TemplateItems.HourDownButtonName, typeof(Button))]
+ [TemplatePart(TemplateItems.HourSelectorName, typeof(DateTimePickerPanel), IsRequired = true)]
+ [TemplatePart(TemplateItems.HourUpButtonName, typeof(Button))]
+ [TemplatePart(TemplateItems.MinuteDownButtonName, typeof(Button))]
+ [TemplatePart(TemplateItems.MinuteSelectorName, typeof(DateTimePickerPanel), IsRequired = true)]
+ [TemplatePart(TemplateItems.MinuteUpButtonName, typeof(Button))]
+ [TemplatePart(TemplateItems.SecondDownButtonName, typeof(Button))]
+ [TemplatePart(TemplateItems.SecondHostName, typeof(Panel))]
+ [TemplatePart(TemplateItems.SecondSelectorName, typeof(DateTimePickerPanel))]
+ [TemplatePart(TemplateItems.SecondUpButtonName, typeof(Button))]
+ [TemplatePart(TemplateItems.PeriodDownButtonName, typeof(Button))]
+ [TemplatePart(TemplateItems.PeriodHostName, typeof(Panel), IsRequired = true)]
+ [TemplatePart(TemplateItems.PeriodSelectorName, typeof(DateTimePickerPanel), IsRequired = true)]
+ [TemplatePart(TemplateItems.PeriodUpButtonName, typeof(Button))]
+ [TemplatePart(TemplateItems.PickerContainerName, typeof(Grid), IsRequired = true)]
+ [TemplatePart(TemplateItems.SecondSpacerName, typeof(Control), IsRequired = true)]
+ [TemplatePart(TemplateItems.ThirdSpacerName, typeof(Control))]
public class TimePickerPresenter : PickerPresenterBase
{
///
@@ -37,7 +36,7 @@ namespace Avalonia.Controls
///
public static readonly StyledProperty MinuteIncrementProperty =
TimePicker.MinuteIncrementProperty.AddOwner();
-
+
///
/// Defines the property
///
@@ -49,7 +48,7 @@ namespace Avalonia.Controls
///
public static readonly StyledProperty ClockIdentifierProperty =
TimePicker.ClockIdentifierProperty.AddOwner();
-
+
///
/// Defines the property
///
@@ -72,26 +71,54 @@ namespace Avalonia.Controls
KeyboardNavigation.TabNavigationProperty.OverrideDefaultValue(KeyboardNavigationMode.Cycle);
}
- // TemplateItems
- private Grid? _pickerContainer;
- private Button? _acceptButton;
- private Button? _dismissButton;
- private Rectangle? _spacer2;
- private Rectangle? _spacer3;
- private Panel? _secondHost;
- private Panel? _periodHost;
- private DateTimePickerPanel? _hourSelector;
- private DateTimePickerPanel? _minuteSelector;
- private DateTimePickerPanel? _secondSelector;
- private DateTimePickerPanel? _periodSelector;
- private Button? _hourUpButton;
- private Button? _minuteUpButton;
- private Button? _secondUpButton;
- private Button? _periodUpButton;
- private Button? _hourDownButton;
- private Button? _minuteDownButton;
- private Button? _secondDownButton;
- private Button? _periodDownButton;
+ private struct TemplateItems
+ {
+ public Grid _pickerContainer;
+ public const string PickerContainerName = "PART_PickerContainer";
+
+ public Button _acceptButton;
+ public const string AcceptButtonName = "PART_AcceptButton";
+ public Button? _dismissButton;
+ public const string DismissButtonName = "PART_DismissButton";
+
+ public Control _secondSpacer; // the 2nd spacer, not seconds of time
+ public const string SecondSpacerName = "PART_SecondSpacer";
+ public Control? _thirdSpacer;
+ public const string ThirdSpacerName = "PART_ThirdSpacer";
+
+ public Panel? _secondHost;
+ public const string SecondHostName = "PART_SecondHost";
+ public Panel _periodHost;
+ public const string PeriodHostName = "PART_PeriodHost";
+
+ public DateTimePickerPanel _hourSelector;
+ public const string HourSelectorName = "PART_HourSelector";
+ public DateTimePickerPanel _minuteSelector;
+ public const string MinuteSelectorName = "PART_MinuteSelector";
+ public DateTimePickerPanel? _secondSelector;
+ public const string SecondSelectorName = "PART_SecondSelector";
+ public DateTimePickerPanel _periodSelector;
+ public const string PeriodSelectorName = "PART_PeriodSelector";
+
+ public Button? _hourUpButton;
+ public const string HourUpButtonName = "PART_HourUpButton";
+ public Button? _minuteUpButton;
+ public const string MinuteUpButtonName = "PART_MinuteUpButton";
+ public Button? _secondUpButton;
+ public const string SecondUpButtonName = "PART_SecondUpButton";
+ public Button? _periodUpButton;
+ public const string PeriodUpButtonName = "PART_PeriodUpButton";
+ public Button? _hourDownButton;
+ public const string HourDownButtonName = "PART_HourDownButton";
+ public Button? _minuteDownButton;
+ public const string MinuteDownButtonName = "PART_MinuteDownButton";
+ public Button? _secondDownButton;
+ public const string SecondDownButtonName = "PART_SecondDownButton";
+ public Button? _periodDownButton;
+ public const string PeriodDownButtonName = "PART_PeriodDownButton";
+ }
+
+ private TemplateItems? _templateItems;
///
/// Gets or sets the minute increment in the selector
@@ -101,7 +128,7 @@ namespace Avalonia.Controls
get => GetValue(MinuteIncrementProperty);
set => SetValue(MinuteIncrementProperty, value);
}
-
+
///
/// Gets or sets the second increment in the selector
///
@@ -119,7 +146,7 @@ namespace Avalonia.Controls
get => GetValue(ClockIdentifierProperty);
set => SetValue(ClockIdentifierProperty, value);
}
-
+
///
/// Gets or sets the current clock identifier, either 12HourClock or 24HourClock
///
@@ -142,54 +169,54 @@ namespace Avalonia.Controls
{
base.OnApplyTemplate(e);
- _pickerContainer = e.NameScope.Get("PART_PickerContainer");
- _periodHost = e.NameScope.Get("PART_PeriodHost");
- _secondHost = e.NameScope.Find("PART_SecondHost");
-
- _hourSelector = e.NameScope.Get("PART_HourSelector");
- _minuteSelector = e.NameScope.Get("PART_MinuteSelector");
- _secondSelector = e.NameScope.Find("PART_SecondSelector");
- _periodSelector = e.NameScope.Get("PART_PeriodSelector");
-
- _spacer2 = e.NameScope.Get("PART_SecondSpacer");
- _spacer3 = e.NameScope.Find("PART_ThirdSpacer");
-
- _acceptButton = e.NameScope.Get("PART_AcceptButton");
- _acceptButton.Click += OnAcceptButtonClicked;
-
- _hourUpButton = e.NameScope.Find("PART_HourUpButton");
- if (_hourUpButton != null)
- _hourUpButton.Click += OnSelectorButtonClick;
- _hourDownButton = e.NameScope.Find("PART_HourDownButton");
- if (_hourDownButton != null)
- _hourDownButton.Click += OnSelectorButtonClick;
-
- _minuteUpButton = e.NameScope.Find("PART_MinuteUpButton");
- if (_minuteUpButton != null)
- _minuteUpButton.Click += OnSelectorButtonClick;
- _minuteDownButton = e.NameScope.Find("PART_MinuteDownButton");
- if (_minuteDownButton != null)
- _minuteDownButton.Click += OnSelectorButtonClick;
-
- _secondUpButton = e.NameScope.Find("PART_SecondUpButton");
- if (_secondUpButton != null)
- _secondUpButton.Click += OnSelectorButtonClick;
- _secondDownButton = e.NameScope.Find("PART_SecondDownButton");
- if (_secondDownButton != null)
- _secondDownButton.Click += OnSelectorButtonClick;
-
- _periodUpButton = e.NameScope.Find("PART_PeriodUpButton");
- if (_periodUpButton != null)
- _periodUpButton.Click += OnSelectorButtonClick;
- _periodDownButton = e.NameScope.Find("PART_PeriodDownButton");
- if (_periodDownButton != null)
- _periodDownButton.Click += OnSelectorButtonClick;
-
- _dismissButton = e.NameScope.Find("PART_DismissButton");
- if (_dismissButton != null)
- _dismissButton.Click += OnDismissButtonClicked;
+ _templateItems = new()
+ {
+ _pickerContainer = e.NameScope.Get(TemplateItems.PickerContainerName),
+ _periodHost = e.NameScope.Get(TemplateItems.PeriodHostName),
+ _secondHost = e.NameScope.Find(TemplateItems.SecondHostName),
+
+ _hourSelector = e.NameScope.Get(TemplateItems.HourSelectorName),
+ _minuteSelector = e.NameScope.Get(TemplateItems.MinuteSelectorName),
+ _secondSelector = e.NameScope.Find(TemplateItems.SecondSelectorName),
+ _periodSelector = e.NameScope.Get(TemplateItems.PeriodSelectorName),
+
+ _secondSpacer = e.NameScope.Get(TemplateItems.SecondSpacerName),
+ _thirdSpacer = e.NameScope.Find(TemplateItems.ThirdSpacerName),
+
+ _acceptButton = e.NameScope.Get(TemplateItems.AcceptButtonName),
+
+ _hourUpButton = SelectorButton(TemplateItems.HourUpButtonName, DateTimePickerPanelType.Hour, SpinDirection.Decrease),
+ _hourDownButton = SelectorButton(TemplateItems.HourDownButtonName, DateTimePickerPanelType.Hour, SpinDirection.Increase),
+
+ _minuteUpButton = SelectorButton(TemplateItems.MinuteUpButtonName, DateTimePickerPanelType.Minute, SpinDirection.Decrease),
+ _minuteDownButton = SelectorButton(TemplateItems.MinuteDownButtonName, DateTimePickerPanelType.Minute, SpinDirection.Increase),
+
+ _secondUpButton = SelectorButton(TemplateItems.SecondUpButtonName, DateTimePickerPanelType.Second, SpinDirection.Decrease),
+ _secondDownButton = SelectorButton(TemplateItems.SecondDownButtonName, DateTimePickerPanelType.Second, SpinDirection.Increase),
+
+ _periodUpButton = SelectorButton(TemplateItems.PeriodUpButtonName, DateTimePickerPanelType.TimePeriod, SpinDirection.Decrease),
+ _periodDownButton = SelectorButton(TemplateItems.PeriodDownButtonName, DateTimePickerPanelType.TimePeriod, SpinDirection.Increase),
+
+ _dismissButton = e.NameScope.Find(TemplateItems.DismissButtonName),
+ };
+
+ _templateItems.Value._acceptButton.Click += OnAcceptButtonClicked;
+ if (_templateItems.Value._dismissButton is { } dismissButton)
+ {
+ dismissButton.Click += OnDismissButtonClicked;
+ }
InitPicker();
+
+ Button? SelectorButton(string name, DateTimePickerPanelType type, SpinDirection direction)
+ {
+ if (e.NameScope.Find(name) is { } button)
+ {
+ button.Click += (s, e) => OnSelectorButtonClick(type, direction);
+ return button;
+ }
+ return null;
+ }
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
@@ -232,100 +259,105 @@ namespace Avalonia.Controls
protected override void OnConfirmed()
{
- var hr = _hourSelector!.SelectedValue;
- var min = _minuteSelector!.SelectedValue;
- var sec = _secondSelector?.SelectedValue ?? 0;
- var per = _periodSelector!.SelectedValue;
-
- if (ClockIdentifier == "12HourClock")
+ if (_templateItems is { } items)
{
- hr = per == 1 ? (hr == 12) ? 12 : hr + 12 : per == 0 && hr == 12 ? 0 : hr;
- }
+ var hr = items._hourSelector.SelectedValue;
+ var min = items._minuteSelector.SelectedValue;
+ var sec = items._secondSelector?.SelectedValue ?? 0;
+ var per = items._periodSelector.SelectedValue;
- SetCurrentValue(TimeProperty, new TimeSpan(hr, min, UseSeconds ? sec : 0));
+ if (ClockIdentifier == "12HourClock")
+ {
+ hr = per == 1 ? (hr == 12) ? 12 : hr + 12 : per == 0 && hr == 12 ? 0 : hr;
+ }
+ SetCurrentValue(TimeProperty, new TimeSpan(hr, min, UseSeconds ? sec : 0));
+ }
base.OnConfirmed();
}
private void InitPicker()
{
- if (_pickerContainer == null)
+ if (_templateItems is not { } items)
return;
bool clock12 = ClockIdentifier == "12HourClock";
- _hourSelector!.MaximumValue = clock12 ? 12 : 23;
- _hourSelector.MinimumValue = clock12 ? 1 : 0;
- _hourSelector.ItemFormat = "%h";
+ items._hourSelector.MaximumValue = clock12 ? 12 : 23;
+ items._hourSelector.MinimumValue = clock12 ? 1 : 0;
+ items._hourSelector.ItemFormat = "%h";
var hr = Time.Hours;
- _hourSelector.SelectedValue = !clock12 ? hr :
+ items._hourSelector.SelectedValue = !clock12 ? hr :
hr > 12 ? hr - 12 : hr == 0 ? 12 : hr;
- _minuteSelector!.MaximumValue = 59;
- _minuteSelector.MinimumValue = 0;
- _minuteSelector.Increment = MinuteIncrement;
- _minuteSelector.ItemFormat = "mm";
- _minuteSelector.SelectedValue = Time.Minutes;
+ items._minuteSelector.MaximumValue = 59;
+ items._minuteSelector.MinimumValue = 0;
+ items._minuteSelector.Increment = MinuteIncrement;
+ items._minuteSelector.ItemFormat = "mm";
+ items._minuteSelector.SelectedValue = Time.Minutes;
- if (_secondSelector is not null)
+ if (items._secondSelector is { } secondSelector)
{
- _secondSelector.MaximumValue = 59;
- _secondSelector.MinimumValue = 0;
- _secondSelector.Increment = SecondIncrement;
- _secondSelector.ItemFormat = "ss";
- _secondSelector.SelectedValue = Time.Seconds;
+ secondSelector.MaximumValue = 59;
+ secondSelector.MinimumValue = 0;
+ secondSelector.Increment = SecondIncrement;
+ secondSelector.ItemFormat = "ss";
+ secondSelector.SelectedValue = Time.Seconds;
}
- _periodSelector!.MaximumValue = 1;
- _periodSelector.MinimumValue = 0;
- _periodSelector.SelectedValue = hr >= 12 ? 1 : 0;
+ items._periodSelector.MaximumValue = 1;
+ items._periodSelector.MinimumValue = 0;
+ items._periodSelector.SelectedValue = hr >= 12 ? 1 : 0;
- SetGrid();
- _hourSelector?.Focus(NavigationMethod.Pointer);
+ SetGrid(items);
+ items._hourSelector.Focus(NavigationMethod.Pointer);
}
- private void SetGrid()
+ private void SetGrid(TemplateItems items)
{
var use24HourClock = ClockIdentifier == "24HourClock";
- var canUseSeconds = _secondHost is not null && _spacer3 is not null;
-
- var columnsD = new ColumnDefinitions();
- columnsD.Add(new ColumnDefinition(GridLength.Star));
- columnsD.Add(new ColumnDefinition(GridLength.Auto));
- columnsD.Add(new ColumnDefinition(GridLength.Star));
- if (canUseSeconds && UseSeconds)
- {
- columnsD.Add(new ColumnDefinition(GridLength.Auto));
- columnsD.Add(new ColumnDefinition(GridLength.Star));
- }
- if (!use24HourClock)
- {
- columnsD.Add(new ColumnDefinition(GridLength.Auto));
- columnsD.Add(new ColumnDefinition(GridLength.Star));
- }
- _pickerContainer!.ColumnDefinitions = columnsD;
+ var columnsD = new ColumnDefinitions
+ {
+ new(GridLength.Star),
+ new(GridLength.Auto),
+ new(GridLength.Star)
+ };
- if (canUseSeconds)
+ if (items._secondHost is not null && items._thirdSpacer is not null)
{
- _spacer2!.IsVisible = UseSeconds;
- _secondHost!.IsVisible = UseSeconds;
- _spacer3!.IsVisible = !use24HourClock;
- _periodHost!.IsVisible = !use24HourClock;
+ if (UseSeconds)
+ {
+ columnsD.Add(new ColumnDefinition(GridLength.Auto));
+ columnsD.Add(new ColumnDefinition(GridLength.Star));
+ }
+
+ items._secondSpacer.IsVisible = UseSeconds;
+ items._secondHost.IsVisible = UseSeconds;
+ items._thirdSpacer.IsVisible = !use24HourClock;
+ items._periodHost.IsVisible = !use24HourClock;
var amPmColumn = (UseSeconds) ? 6 : 4;
- Grid.SetColumn(_spacer2, UseSeconds ? 3 : 0);
- Grid.SetColumn(_secondHost, UseSeconds ? 4 : 0);
- Grid.SetColumn(_spacer3, use24HourClock ? 0 : amPmColumn-1);
- Grid.SetColumn(_periodHost, use24HourClock ? 0 : amPmColumn);
+ Grid.SetColumn(items._secondSpacer, UseSeconds ? 3 : 0);
+ Grid.SetColumn(items._secondHost, UseSeconds ? 4 : 0);
+ Grid.SetColumn(items._thirdSpacer, use24HourClock ? 0 : amPmColumn - 1);
+ Grid.SetColumn(items._periodHost, use24HourClock ? 0 : amPmColumn);
}
else
{
- _spacer2!.IsVisible = !use24HourClock;
- _periodHost!.IsVisible = !use24HourClock;
- Grid.SetColumn(_spacer2, use24HourClock ? 0 : 3);
- Grid.SetColumn(_periodHost, use24HourClock ? 0 : 4);
+ items._secondSpacer.IsVisible = !use24HourClock;
+ items._periodHost.IsVisible = !use24HourClock;
+ Grid.SetColumn(items._secondSpacer, use24HourClock ? 0 : 3);
+ Grid.SetColumn(items._periodHost, use24HourClock ? 0 : 4);
}
+
+ if (!use24HourClock)
+ {
+ columnsD.Add(new ColumnDefinition(GridLength.Auto));
+ columnsD.Add(new ColumnDefinition(GridLength.Star));
+ }
+
+ items._pickerContainer.ColumnDefinitions = columnsD;
}
private void OnDismissButtonClicked(object? sender, RoutedEventArgs e)
@@ -338,33 +370,37 @@ namespace Avalonia.Controls
OnConfirmed();
}
- private void OnSelectorButtonClick(object? sender, RoutedEventArgs e)
+ private void OnSelectorButtonClick(DateTimePickerPanelType type, SpinDirection direction)
{
- if (sender == _hourUpButton)
- _hourSelector!.ScrollUp();
- else if (sender == _hourDownButton)
- _hourSelector!.ScrollDown();
- else if (sender == _minuteUpButton)
- _minuteSelector!.ScrollUp();
- else if (sender == _minuteDownButton)
- _minuteSelector!.ScrollDown();
- else if (sender == _secondUpButton)
- _secondSelector!.ScrollUp();
- else if (sender == _secondDownButton)
- _secondSelector!.ScrollDown();
- else if (sender == _periodUpButton)
- _periodSelector!.ScrollUp();
- else if (sender == _periodDownButton)
- _periodSelector!.ScrollDown();
+ var target = type switch
+ {
+ DateTimePickerPanelType.Hour => _templateItems?._hourSelector,
+ DateTimePickerPanelType.Minute => _templateItems?._minuteSelector,
+ DateTimePickerPanelType.Second => _templateItems?._secondSelector,
+ DateTimePickerPanelType.TimePeriod => _templateItems?._periodSelector,
+ _ => throw new NotImplementedException(),
+ };
+
+ switch (direction)
+ {
+ case SpinDirection.Increase:
+ target?.ScrollDown();
+ break;
+ case SpinDirection.Decrease:
+ target?.ScrollUp();
+ break;
+ default:
+ throw new NotImplementedException();
+ }
}
internal double GetOffsetForPopup()
{
- if (_hourSelector is null)
+ if (_templateItems is not { } items)
return 0;
- var acceptDismissButtonHeight = _acceptButton != null ? _acceptButton.Bounds.Height : 41;
- return -(MaxHeight - acceptDismissButtonHeight) / 2 - (_hourSelector.ItemHeight / 2);
+ var acceptDismissButtonHeight = items._acceptButton.Bounds.Height;
+ return -(MaxHeight - acceptDismissButtonHeight) / 2 - (items._hourSelector.ItemHeight / 2);
}
}
}