diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index 681c7747c9..ec7a11067c 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -29,6 +29,9 @@ ScrollViewer.HorizontalScrollBarVisibility="Disabled"> + + + diff --git a/samples/ControlCatalog/Pages/DateTimePickerPage.xaml b/samples/ControlCatalog/Pages/DateTimePickerPage.xaml new file mode 100644 index 0000000000..af6b6e8605 --- /dev/null +++ b/samples/ControlCatalog/Pages/DateTimePickerPage.xaml @@ -0,0 +1,123 @@ + + + DatePicker and TimePicker + + + + + A simple DatePicker with a header + + + + + + + + + <DatePicker Header="Pick a date" /> + + + + + + + A DatePicker with day formatted and year hidden. + + + + + + + + + <DatePicker DayFormat="d (ddd)" YearVisible="False" /> + + + + + + + + + A simple TimePicker. + + + + + + + + + <TimePicker /> + + + + + + + A TimePicker with a header and minute increments specified. + + + + + + + + + <TimePicker Header="Arrival time" MinuteIncrement="15" /> + + + + + + + A TimePicker using a 12-hour clock. + + + + + + + + + <TimePicker ClockIdentifier="12HourClock" Header="12 hour clock" /> + + + + + + + A TimePicker using a 24-hour clock. + + + + + + + + + <TimePicker ClockIdentifier="24HourClock" Header="24 hour clock" /> + + + + + + + + + diff --git a/samples/ControlCatalog/Pages/DateTimePickerPage.xaml.cs b/samples/ControlCatalog/Pages/DateTimePickerPage.xaml.cs new file mode 100644 index 0000000000..6c7ae3437e --- /dev/null +++ b/samples/ControlCatalog/Pages/DateTimePickerPage.xaml.cs @@ -0,0 +1,30 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace ControlCatalog.Pages +{ + public class DateTimePickerPage : UserControl + { + public DateTimePickerPage() + { + this.InitializeComponent(); + this.FindControl("DatePickerDesc").Text = "Use a DatePicker to let users set a date in your app, " + + "for example to schedule an appointment. The DatePicker displays three controls for month, day, and year. " + + "These controls are easy to use with touch or mouse, and they can be styled and configured in several different ways. " + + "Order of month, day, and year is dynamically set based on user date settings"; + + this.FindControl("TimePickerDesc").Text = "Use a TimePicker to let users set a time in your app, for example " + + "to set a reminder. The TimePicker displays three controls for hour, minute, and AM / PM(if necessary).These controls " + + "are easy to use with touch or mouse, and they can be styled and configured in several different ways. " + + "12 - hour or 24 - hour clock and visiblility of AM / PM is dynamically set based on user time settings, or can be overridden."; + + + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/src/Avalonia.Controls/DateTimePickers/DatePicker.cs b/src/Avalonia.Controls/DateTimePickers/DatePicker.cs new file mode 100644 index 0000000000..5d3311e8c6 --- /dev/null +++ b/src/Avalonia.Controls/DateTimePickers/DatePicker.cs @@ -0,0 +1,412 @@ +using Avalonia.Controls.Primitives; +using Avalonia.Controls.Shapes; +using Avalonia.Controls.Templates; +using Avalonia.Interactivity; +using System; +using System.Collections.Generic; +using System.Globalization; + +namespace Avalonia.Controls +{ + /// + /// A control to allow the user to select a date + /// + public class DatePicker : TemplatedControl + { + /// + /// Define the Property + /// + public static readonly DirectProperty DayFormatProperty = + AvaloniaProperty.RegisterDirect(nameof(DayFormat), + x => x.DayFormat, (x, v) => x.DayFormat = v); + + /// + /// Defines the Property + /// + public static readonly DirectProperty DayVisibleProperty = + AvaloniaProperty.RegisterDirect(nameof(DayVisible), + x => x.DayVisible, (x, v) => x.DayVisible = v); + + /// + /// Defines the Property + /// + public static readonly StyledProperty HeaderProperty = + AvaloniaProperty.Register(nameof(Header)); + + /// + /// Defines the Property + /// + public static readonly StyledProperty HeaderTemplateProperty = + AvaloniaProperty.Register(nameof(HeaderTemplate)); + + /// + /// Defines the Property + /// + public static readonly DirectProperty MaxYearProperty = + AvaloniaProperty.RegisterDirect(nameof(MaxYear), + x => x.MaxYear, (x, v) => x.MaxYear = v); + + /// + /// Defines the Property + /// + public static readonly DirectProperty MinYearProperty = + AvaloniaProperty.RegisterDirect(nameof(MinYear), + x => x.MinYear, (x, v) => x.MinYear = v); + + /// + /// Defines the Property + /// + public static readonly DirectProperty MonthFormatProperty = + AvaloniaProperty.RegisterDirect(nameof(MonthFormat), + x => x.MonthFormat, (x, v) => x.MonthFormat = v); + + /// + /// Defines the Property + /// + public static readonly DirectProperty MonthVisibleProperty = + AvaloniaProperty.RegisterDirect(nameof(MonthVisible), + x => x.MonthVisible, (x, v) => x.MonthVisible = v); + + /// + /// Defiens the Property + /// + public static readonly DirectProperty YearFormatProperty = + AvaloniaProperty.RegisterDirect(nameof(YearFormat), + x => x.YearFormat, (x, v) => x.YearFormat = v); + + /// + /// Defines the Property + /// + public static readonly DirectProperty YearVisibleProperty = + AvaloniaProperty.RegisterDirect(nameof(YearVisible), + x => x.YearVisible, (x, v) => x.YearVisible = v); + + /// + /// Defines the Property + /// + public static readonly DirectProperty SelectedDateProperty = + AvaloniaProperty.RegisterDirect(nameof(SelectedDate), + x => x.SelectedDate, (x, v) => x.SelectedDate = v); + + //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; + + private string _dayFormat = "%d"; + private bool _dayVisible = true; + private DateTimeOffset _maxYear; + private DateTimeOffset _minYear; + private string _monthFormat = "MMMM"; + private bool _monthVisible = true; + private string _yearFormat = "yyyy"; + private bool _yearVisible = true; + private DateTimeOffset? _selectedDate; + + public DatePicker() + { + PseudoClasses.Set(":hasnodate", true); + var now = DateTimeOffset.Now; + _minYear = new DateTimeOffset(now.Date.Year - 100, 1, 1, 0, 0, 0, now.Offset); + _maxYear = new DateTimeOffset(now.Date.Year + 100, 12, 31, 0, 0, 0, now.Offset); + } + + public string DayFormat + { + get => _dayFormat; + set => SetAndRaise(DayFormatProperty, ref _dayFormat, value); + } + + /// + /// Gets or sets whether the day is visible + /// + public bool DayVisible + { + get => _dayVisible; + set + { + SetAndRaise(DayVisibleProperty, ref _dayVisible, value); + SetGrid(); + } + } + + /// + /// Gets or sets the DatePicker header + /// + public object Header + { + get => GetValue(HeaderProperty); + set => SetValue(HeaderProperty, value); + } + + /// + /// Gets or sets the header template + /// + public IDataTemplate HeaderTemplate + { + get => GetValue(HeaderTemplateProperty); + set => SetValue(HeaderTemplateProperty, value); + } + + /// + /// Gets or sets the maximum year for the picker + /// + public DateTimeOffset MaxYear + { + get => _maxYear; + set + { + if (value < MinYear) + throw new InvalidOperationException("MaxDate cannot be less than MinDate"); + SetAndRaise(MaxYearProperty, ref _maxYear, value); + + if (SelectedDate.HasValue && SelectedDate.Value > value) + SelectedDate = value; + } + } + + /// + /// Gets or sets the minimum year for the picker + /// + public DateTimeOffset MinYear + { + get => _minYear; + set + { + if (value > MaxYear) + throw new InvalidOperationException("MinDate cannot be greater than MaxDate"); + SetAndRaise(MinYearProperty, ref _minYear, value); + + if (SelectedDate.HasValue && SelectedDate.Value < value) + SelectedDate = value; + } + } + + /// + /// Gets or sets the month format + /// + public string MonthFormat + { + get => _monthFormat; + set => SetAndRaise(MonthFormatProperty, ref _monthFormat, value); + } + + /// + /// Gets or sets whether the month is visible + /// + public bool MonthVisible + { + get => _monthVisible; + set + { + SetAndRaise(MonthVisibleProperty, ref _monthVisible, value); + SetGrid(); + } + } + + /// + /// Gets or sets the year format + /// + public string YearFormat + { + get => _yearFormat; + set => SetAndRaise(YearFormatProperty, ref _yearFormat, value); + } + + /// + /// Gets or sets whether the year is visible + /// + public bool YearVisible + { + get => _yearVisible; + set + { + SetAndRaise(YearVisibleProperty, ref _yearVisible, value); + SetGrid(); + } + } + + /// + /// Gets or sets the Selected Date for the picker, can be null + /// + public DateTimeOffset? SelectedDate + { + get => _selectedDate; + set + { + var old = _selectedDate; + SetAndRaise(SelectedDateProperty, ref _selectedDate, value); + SetSelectedDateText(); + OnSelectedDateChanged(this, new DatePickerSelectedValueChangedEventArgs(old, 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