using Avalonia.Automation.Peers;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Data;
using Avalonia.Interactivity;
using Avalonia.Layout;
using System;
using System.Collections.Generic;
using System.Globalization;
namespace Avalonia.Controls
{
///
/// A control to allow the user to select a date
///
[TemplatePart("PART_ButtonContentGrid", typeof(Grid))]
[TemplatePart("PART_DayTextBlock", typeof(TextBlock))]
[TemplatePart("PART_FirstSpacer", typeof(Rectangle))]
[TemplatePart("PART_FlyoutButton", typeof(Button))]
[TemplatePart("PART_MonthTextBlock", typeof(TextBlock))]
[TemplatePart("PART_PickerPresenter", typeof(DatePickerPresenter))]
[TemplatePart("PART_Popup", typeof(Popup))]
[TemplatePart("PART_SecondSpacer", typeof(Rectangle))]
[TemplatePart("PART_YearTextBlock", typeof(TextBlock))]
[PseudoClasses(":hasnodate")]
public class DatePicker : TemplatedControl
{
///
/// Define the Property
///
public static readonly StyledProperty DayFormatProperty =
AvaloniaProperty.Register(nameof(DayFormat), "%d");
///
/// Defines the Property
///
public static readonly StyledProperty DayVisibleProperty =
AvaloniaProperty.Register(nameof(DayVisible), true);
///
/// Defines the Property
///
public static readonly StyledProperty MaxYearProperty =
AvaloniaProperty.Register(nameof(MaxYear), DateTimeOffset.MaxValue, coerce: CoerceMaxYear);
///
/// Defines the Property
///
public static readonly StyledProperty MinYearProperty =
AvaloniaProperty.Register(nameof(MinYear), DateTimeOffset.MinValue, coerce: CoerceMinYear);
///
/// Defines the Property
///
public static readonly StyledProperty MonthFormatProperty =
AvaloniaProperty.Register(nameof(MonthFormat), "MMMM");
///
/// Defines the Property
///
public static readonly StyledProperty MonthVisibleProperty =
AvaloniaProperty.Register(nameof(MonthVisible), true);
///
/// Defines the Property
///
public static readonly StyledProperty YearFormatProperty =
AvaloniaProperty.Register(nameof(YearFormat), "yyyy");
///
/// Defines the Property
///
public static readonly StyledProperty YearVisibleProperty =
AvaloniaProperty.Register(nameof(YearVisible), true);
///
/// Defines the Property
///
public static readonly StyledProperty SelectedDateProperty =
AvaloniaProperty.Register(nameof(SelectedDate),
defaultBindingMode: BindingMode.TwoWay, enableDataValidation: true);
// Template Items
private Button? _flyoutButton;
private TextBlock? _dayText;
private TextBlock? _monthText;
private TextBlock? _yearText;
private Grid? _container;
private Rectangle? _spacer1;
private Rectangle? _spacer2;
private Popup? _popup;
private DatePickerPresenter? _presenter;
private bool _areControlsAvailable;
public DatePicker()
{
PseudoClasses.Set(":hasnodate", true);
var now = DateTimeOffset.Now;
SetCurrentValue(MinYearProperty, new DateTimeOffset(now.Date.Year - 100, 1, 1, 0, 0, 0, now.Offset));
SetCurrentValue(MaxYearProperty, new DateTimeOffset(now.Date.Year + 100, 12, 31, 0, 0, 0, now.Offset));
}
private static void OnGridVisibilityChanged(DatePicker sender, AvaloniaPropertyChangedEventArgs e) => sender.SetGrid();
public string DayFormat
{
get => GetValue(DayFormatProperty);
set => SetValue(DayFormatProperty, value);
}
///
/// Gets or sets whether the day is visible
///
public bool DayVisible
{
get => GetValue(DayVisibleProperty);
set => SetValue(DayVisibleProperty, value);
}
///
/// Gets or sets the maximum year for the picker
///
public DateTimeOffset MaxYear
{
get => GetValue(MaxYearProperty);
set => SetValue(MaxYearProperty, value);
}
private static DateTimeOffset CoerceMaxYear(AvaloniaObject sender, DateTimeOffset value)
{
if (value < sender.GetValue(MinYearProperty))
{
throw new InvalidOperationException($"{MaxYearProperty.Name} cannot be less than {MinYearProperty.Name}");
}
return value;
}
private void OnMaxYearChanged(DateTimeOffset? value)
{
if (SelectedDate.HasValue && SelectedDate.Value > value)
SetCurrentValue(SelectedDateProperty, value);
}
///
/// Gets or sets the minimum year for the picker
///
public DateTimeOffset MinYear
{
get => GetValue(MinYearProperty);
set => SetValue(MinYearProperty, value);
}
private static DateTimeOffset CoerceMinYear(AvaloniaObject sender, DateTimeOffset value)
{
if (value > sender.GetValue(MaxYearProperty))
{
throw new InvalidOperationException($"{MinYearProperty.Name} cannot be greater than {MaxYearProperty.Name}");
}
return value;
}
private void OnMinYearChanged(DateTimeOffset? value)
{
if (SelectedDate.HasValue && SelectedDate.Value < value)
SetCurrentValue(SelectedDateProperty, value);
}
///
/// Gets or sets the month format
///
public string MonthFormat
{
get => GetValue(MonthFormatProperty);
set => SetValue(MonthFormatProperty, value);
}
///
/// Gets or sets whether the month is visible
///
public bool MonthVisible
{
get => GetValue(MonthVisibleProperty);
set => SetValue(MonthVisibleProperty, value);
}
///
/// Gets or sets the year format
///
public string YearFormat
{
get => GetValue(YearFormatProperty);
set => SetValue(YearFormatProperty, value);
}
///
/// Gets or sets whether the year is visible
///
public bool YearVisible
{
get => GetValue(YearVisibleProperty);
set => SetValue(YearVisibleProperty, value);
}
///
/// Gets or sets the Selected Date for the picker, can be null
///
public DateTimeOffset? SelectedDate
{
get => GetValue(SelectedDateProperty);
set => SetValue(SelectedDateProperty, value);
}
///
/// Raised when the changes
///
public event EventHandler? SelectedDateChanged;
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
_areControlsAvailable = false;
if (_flyoutButton != null)
_flyoutButton.Click -= OnFlyoutButtonClicked;
if (_presenter != null)
{
_presenter.Confirmed -= OnConfirmed;
_presenter.Dismissed -= OnDismissPicker;
}
base.OnApplyTemplate(e);
_flyoutButton = e.NameScope.Find