diff --git a/demo/Ursa.Demo/Pages/DatePickerDemo.axaml b/demo/Ursa.Demo/Pages/DatePickerDemo.axaml
index 254a1ea..d7810a5 100644
--- a/demo/Ursa.Demo/Pages/DatePickerDemo.axaml
+++ b/demo/Ursa.Demo/Pages/DatePickerDemo.axaml
@@ -7,5 +7,8 @@
x:Class="Ursa.Demo.Pages.DatePickerDemo">
+
+
+
diff --git a/src/Ursa.Themes.Semi/Controls/Calendar.axaml b/src/Ursa.Themes.Semi/Controls/Calendar.axaml
index 1264422..b8184d4 100644
--- a/src/Ursa.Themes.Semi/Controls/Calendar.axaml
+++ b/src/Ursa.Themes.Semi/Controls/Calendar.axaml
@@ -15,6 +15,7 @@
+
@@ -118,6 +119,7 @@
+
@@ -159,6 +161,7 @@
+
diff --git a/src/Ursa.Themes.Semi/Controls/DatePicker.axaml b/src/Ursa.Themes.Semi/Controls/DatePicker.axaml
new file mode 100644
index 0000000..260bb58
--- /dev/null
+++ b/src/Ursa.Themes.Semi/Controls/DatePicker.axaml
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Ursa.Themes.Semi/Controls/_index.axaml b/src/Ursa.Themes.Semi/Controls/_index.axaml
index 24549cf..232557f 100644
--- a/src/Ursa.Themes.Semi/Controls/_index.axaml
+++ b/src/Ursa.Themes.Semi/Controls/_index.axaml
@@ -8,6 +8,7 @@
+
diff --git a/src/Ursa/Controls/DateTimePicker/CalendarDayButton.cs b/src/Ursa/Controls/DateTimePicker/CalendarDayButton.cs
index ecc67a0..fc04d9e 100644
--- a/src/Ursa/Controls/DateTimePicker/CalendarDayButton.cs
+++ b/src/Ursa/Controls/DateTimePicker/CalendarDayButton.cs
@@ -24,8 +24,7 @@ public class CalendarDayButton : ContentControl
private static HashSet _pseudoClasses =
[
- PseudoClassName.PC_Selected, PC_EndDate, PC_PreviewStartDate,
- PC_PreviewEndDate, PseudoClassName.PC_Selected, PC_InRange
+ PseudoClassName.PC_Selected, PC_StartDate, PC_EndDate, PC_PreviewStartDate, PC_PreviewEndDate, PC_InRange
];
public static readonly RoutedEvent DateSelectedEvent =
@@ -127,7 +126,7 @@ public class CalendarDayButton : ContentControl
set
{
_isSelected = value;
- PseudoClasses.Set(PseudoClassName.PC_Selected, value);
+ SetPseudoClass(PseudoClassName.PC_Selected);
}
}
@@ -170,20 +169,6 @@ public class CalendarDayButton : ContentControl
remove => RemoveHandler(DateSelectedEvent, value);
}
- protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
- {
- base.OnApplyTemplate(e);
- /*
- PseudoClasses.Set(PC_Today, IsToday);
- PseudoClasses.Set(PC_StartDate, IsStartDate);
- PseudoClasses.Set(PC_EndDate, IsEndDate);
- PseudoClasses.Set(PC_PreviewStartDate, IsPreviewStartDate);
- PseudoClasses.Set(PC_PreviewEndDate, IsPreviewEndDate);
- PseudoClasses.Set(PC_InRange, IsInRange);
- PseudoClasses.Set(PseudoClassName.PC_Selected, IsSelected);
- */
- }
-
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);
diff --git a/src/Ursa/Controls/DateTimePicker/CalendarView.cs b/src/Ursa/Controls/DateTimePicker/CalendarView.cs
index 265eeba..b3c0063 100644
--- a/src/Ursa/Controls/DateTimePicker/CalendarView.cs
+++ b/src/Ursa/Controls/DateTimePicker/CalendarView.cs
@@ -1,4 +1,5 @@
using System.Globalization;
+using System.Runtime.CompilerServices;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
@@ -60,6 +61,10 @@ public class CalendarView : TemplatedControl
private Button? _yearButton;
private Grid? _yearGrid;
+ private DateTime? _start;
+ private DateTime? _end;
+ private DateTime? _previewStart;
+ private DateTime? _previewEnd;
static CalendarView()
{
@@ -329,6 +334,7 @@ public class CalendarView : TemplatedControl
}
FadeOutDayButtons();
+ MarkDates(_start, _end, _previewStart, _previewEnd);
}
private void UpdateYearButtons()
@@ -414,7 +420,10 @@ public class CalendarView : TemplatedControl
if (e.Date.Month != ContextCalendar.Month)
{
ContextCalendar.Month = e.Date.Month;
+ ContextCalendar.Year = e.Date.Year;
+ ContextCalendar.Day = 1;
UpdateDayButtons();
+ UpdateHeaderButtons();
}
OnDateSelected?.Invoke(sender, e);
@@ -535,4 +544,47 @@ public class CalendarView : TemplatedControl
IsEnabledProperty.SetValue(canForward, _previousButton, _fastPreviousButton);
IsEnabledProperty.SetValue(canNext, _nextButton, _fastNextButton);
}
+
+ public void MarkDates(DateTime? startDate = null, DateTime? endDate = null, DateTime? previewStartDate = null, DateTime? previewEndDate = null)
+ {
+ _start = startDate;
+ _end = endDate;
+ _previewStart = previewStartDate;
+ _previewEnd = previewEndDate;
+ if (_monthGrid?.Children is null) return;
+ DateTime start = startDate ?? DateTime.MaxValue;
+ DateTime end = endDate ?? DateTime.MinValue;
+ DateTime previewStart = previewStartDate ?? DateTime.MaxValue;
+ DateTime previewEnd = previewEndDate ?? DateTime.MinValue;
+ DateTime rangeStart = DateTimeHelper.Min(start, previewStart);
+ DateTime rangeEnd = DateTimeHelper.Max(end, previewEnd);
+ foreach (var child in _monthGrid.Children)
+ {
+ if (child is not CalendarDayButton { DataContext: DateTime d } button) continue;
+ button.ResetSelection();
+ if(d.Month != ContextCalendar.Month) continue;
+ if (d < rangeEnd && d > rangeStart) button.IsInRange = true;
+ if (d == previewStart) button.IsPreviewStartDate = true;
+ if (d == previewEnd) button.IsPreviewEndDate = true;
+ if (d == startDate) button.IsStartDate = true;
+ if (d == endDate) button.IsEndDate = true;
+ if (d == startDate && d == endDate) button.IsSelected = true;
+ }
+ }
+
+ public void ClearSelection()
+ {
+ _start = null;
+ _end = null;
+ _previewStart = null;
+ _previewEnd = null;
+ if (_monthGrid?.Children is null) return;
+ foreach (var child in _monthGrid.Children)
+ {
+ if (child is not CalendarDayButton button) continue;
+ button.IsStartDate = false;
+ button.IsEndDate = false;
+ button.IsInRange = false;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Ursa/Controls/DateTimePicker/DatePicker.cs b/src/Ursa/Controls/DateTimePicker/DatePicker.cs
index fbcbed8..8463aa5 100644
--- a/src/Ursa/Controls/DateTimePicker/DatePicker.cs
+++ b/src/Ursa/Controls/DateTimePicker/DatePicker.cs
@@ -1,8 +1,162 @@
-using Avalonia.Controls.Primitives;
+using System.Globalization;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Metadata;
+using Avalonia.Controls.Primitives;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using Irihi.Avalonia.Shared.Contracts;
+using Irihi.Avalonia.Shared.Helpers;
namespace Ursa.Controls;
-public class DatePicker: DatePickerBase
+[TemplatePart(PART_Button, typeof(Button))]
+[TemplatePart(PART_Popup, typeof(Popup))]
+[TemplatePart(PART_TextBox, typeof(TextBox))]
+[TemplatePart(PART_Calendar, typeof(CalendarView))]
+public class DatePicker: DatePickerBase, IClearControl
{
+ public const string PART_Button = "PART_Button";
+ public const string PART_Popup = "PART_Popup";
+ public const string PART_TextBox = "PART_TextBox";
+ public const string PART_Calendar = "PART_Calendar";
+ private Button? _button;
+ private Popup? _popup;
+ private TextBox? _textBox;
+ private CalendarView? _calendar;
+
+ public static readonly StyledProperty SelectedDateProperty = AvaloniaProperty.Register(
+ nameof(SelectedDate));
+
+ public DateTime? SelectedDate
+ {
+ get => GetValue(SelectedDateProperty);
+ set => SetValue(SelectedDateProperty, value);
+ }
+
+ static DatePicker()
+ {
+ SelectedDateProperty.Changed.AddClassHandler((picker, args) =>
+ picker.OnSelectionChanged(args));
+ }
+
+ private void OnSelectionChanged(AvaloniaPropertyChangedEventArgs args)
+ {
+ if (args.NewValue.Value is null)
+ {
+ _calendar?.ClearSelection();
+ _textBox?.Clear();
+ }
+ else
+ {
+ _calendar?.MarkDates(startDate: args.NewValue.Value, endDate: args.NewValue.Value);
+ _textBox?.SetValue(TextBox.TextProperty, args.NewValue.Value.Value.ToString(DisplayFormat ?? "yyyy-MM-dd"));
+ }
+ }
+
+ protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
+ {
+ base.OnApplyTemplate(e);
+
+ GotFocusEvent.RemoveHandler(OnTextBoxGetFocus, _textBox);
+ TextBox.TextChangedEvent.RemoveHandler(OnTextChanged, _textBox);
+ PointerPressedEvent.RemoveHandler(OnTextBoxPointerPressed, _textBox);
+ Button.ClickEvent.RemoveHandler(OnButtonClick, _button);
+ if (_calendar != null)
+ {
+ _calendar.OnDateSelected -= OnDateSelected;
+ }
+
+ _button = e.NameScope.Find