diff --git a/demo/Ursa.Demo/Pages/DatePickerDemo.axaml b/demo/Ursa.Demo/Pages/DatePickerDemo.axaml
index dbe53bf..2ccbdb9 100644
--- a/demo/Ursa.Demo/Pages/DatePickerDemo.axaml
+++ b/demo/Ursa.Demo/Pages/DatePickerDemo.axaml
@@ -8,6 +8,6 @@
-
+
diff --git a/src/Ursa.Themes.Semi/Controls/Calendar.axaml b/src/Ursa.Themes.Semi/Controls/Calendar.axaml
index 6bea24a..e0efb23 100644
--- a/src/Ursa.Themes.Semi/Controls/Calendar.axaml
+++ b/src/Ursa.Themes.Semi/Controls/Calendar.axaml
@@ -5,7 +5,7 @@
-
+
@@ -120,15 +120,15 @@
-
+
-
+
_pseudoClasses =
+ [
+ PseudoClassName.PC_Selected, PC_EndDate, PC_PreviewStartDate,
+ PC_PreviewEndDate, PseudoClassName.PC_Selected, PC_InRange
+ ];
+
+ public static readonly RoutedEvent DateSelectedEvent =
+ RoutedEvent.Register(
+ nameof(DateSelected), RoutingStrategies.Bubble);
+
+ public static readonly RoutedEvent DatePreviewedEvent =
+ RoutedEvent.Register(
+ nameof(DatePreviewed), RoutingStrategies.Bubble);
+
+ private bool _isBlackout;
+
+ private bool _isEndDate;
+
+ private bool _isInRange;
+
+ private bool _isNotCurrentMonth;
+
+ private bool _isPreviewEndDate;
+
+ private bool _isPreviewStartDate;
+
+ private bool _isSelected;
+
+ private bool _isStartDate;
private bool _isToday;
+
+ static CalendarDayButton()
+ {
+ PressedMixin.Attach();
+ }
+
+ // internal CalendarDisplayControl? Owner { get; set; }
+
public bool IsToday
{
get => _isToday;
@@ -36,30 +70,27 @@ public class CalendarDayButton: ContentControl
PseudoClasses.Set(PC_Today, value);
}
}
-
- private bool _isStartDate;
+
public bool IsStartDate
{
get => _isStartDate;
set
{
_isStartDate = value;
- PseudoClasses.Set(PC_StartDate, value);
+ SetPseudoClass(PC_StartDate);
}
}
-
- private bool _isEndDate;
+
public bool IsEndDate
{
get => _isEndDate;
set
{
_isEndDate = value;
- PseudoClasses.Set(PC_EndDate, value);
+ SetPseudoClass(PC_EndDate);
}
}
-
- private bool _isPreviewStartDate;
+
public bool IsPreviewStartDate
{
get => _isPreviewStartDate;
@@ -69,8 +100,7 @@ public class CalendarDayButton: ContentControl
PseudoClasses.Set(PC_PreviewStartDate, value);
}
}
-
- private bool _isPreviewEndDate;
+
public bool IsPreviewEndDate
{
get => _isPreviewEndDate;
@@ -80,8 +110,7 @@ public class CalendarDayButton: ContentControl
PseudoClasses.Set(PC_PreviewEndDate, value);
}
}
-
- private bool _isInRange;
+
public bool IsInRange
{
get => _isInRange;
@@ -92,7 +121,6 @@ public class CalendarDayButton: ContentControl
}
}
- private bool _isSelected;
public bool IsSelected
{
get => _isSelected;
@@ -102,10 +130,9 @@ public class CalendarDayButton: ContentControl
PseudoClasses.Set(PseudoClassName.PC_Selected, value);
}
}
-
- private bool _isBlackout;
+
///
- /// Notice: IsBlackout is not equivalent to not IsEnabled. Blackout dates still react to pointerover actions.
+ /// Notice: IsBlackout is not equivalent to not IsEnabled. Blackout dates still react to pointerover actions.
///
public bool IsBlackout
{
@@ -116,10 +143,10 @@ public class CalendarDayButton: ContentControl
PseudoClasses.Set(PC_Blackout, value);
}
}
-
- private bool _isNotCurrentMonth;
+
///
- /// Notice: IsNotCurrentMonth is not equivalent to not IsEnabled. Not current month dates still react to pointerover and press action.
+ /// Notice: IsNotCurrentMonth is not equivalent to not IsEnabled. Not current month dates still react to pointerover
+ /// and press action.
///
public bool IsNotCurrentMonth
{
@@ -130,33 +157,23 @@ public class CalendarDayButton: ContentControl
PseudoClasses.Set(PC_NotCurrentMonth, value);
}
}
-
- public static readonly RoutedEvent DateSelectedEvent = RoutedEvent.Register(
- nameof(DateSelected), RoutingStrategies.Bubble);
-
+
public event EventHandler DateSelected
{
add => AddHandler(DateSelectedEvent, value);
remove => RemoveHandler(DateSelectedEvent, value);
}
-
- public static readonly RoutedEvent DatePreviewedEvent = RoutedEvent.Register(
- nameof(DatePreviewed), RoutingStrategies.Bubble);
-
+
public event EventHandler DatePreviewed
{
add => AddHandler(DateSelectedEvent, value);
- remove => RemoveHandler(DateSelectedEvent, value);
- }
-
- static CalendarDayButton()
- {
- PressedMixin.Attach();
+ 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);
@@ -164,23 +181,40 @@ public class CalendarDayButton: ContentControl
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);
- if (this.DataContext is DateTime d)
- {
+ if (DataContext is DateTime d)
RaiseEvent(new CalendarDayButtonEventArgs(d) { RoutedEvent = DateSelectedEvent, Source = this });
- }
}
protected override void OnPointerEntered(PointerEventArgs e)
{
base.OnPointerEntered(e);
- if (this.DataContext is DateTime d)
- {
+ if (DataContext is DateTime d)
RaiseEvent(new CalendarDayButtonEventArgs(d) { RoutedEvent = DateSelectedEvent, Source = this });
+ }
+
+ internal void ResetSelection()
+ {
+ foreach (var pc in _pseudoClasses)
+ {
+ PseudoClasses.Set(pc, false);
}
}
+
+ private void SetPseudoClass(string s)
+ {
+ if (_pseudoClasses.Contains(s))
+ {
+ foreach (var pc in _pseudoClasses)
+ {
+ PseudoClasses.Set(pc, false);
+ }
+ }
+ PseudoClasses.Set(s, true);
+ }
}
\ No newline at end of file
diff --git a/src/Ursa/Controls/DateTimePicker/Calendar.cs b/src/Ursa/Controls/DateTimePicker/CalendarDisplayControl.cs
similarity index 89%
rename from src/Ursa/Controls/DateTimePicker/Calendar.cs
rename to src/Ursa/Controls/DateTimePicker/CalendarDisplayControl.cs
index 9253d52..61a0117 100644
--- a/src/Ursa/Controls/DateTimePicker/Calendar.cs
+++ b/src/Ursa/Controls/DateTimePicker/CalendarDisplayControl.cs
@@ -17,7 +17,7 @@ namespace Ursa.Controls;
[TemplatePart(PART_HeaderButton, typeof(Button))]
[TemplatePart(PART_MonthView, typeof(CalendarMonthView))]
[TemplatePart(PART_YearView, typeof(CalendarYearView))]
-public class Calendar: TemplatedControl
+public class CalendarDisplayControl: TemplatedControl
{
public const string PART_NextYearButton = "PART_NextYearButton";
public const string PART_PreviousYearButton = "PART_PreviousYearButton";
@@ -37,7 +37,7 @@ public class Calendar: TemplatedControl
private Button? _headerButton;
- public static readonly StyledProperty SelectedDateProperty = AvaloniaProperty.Register(nameof(SelectedDate), DateTime.Now);
+ public static readonly StyledProperty SelectedDateProperty = AvaloniaProperty.Register(nameof(SelectedDate), DateTime.Now);
public DateTime SelectedDate
{
get => GetValue(SelectedDateProperty);
@@ -45,7 +45,7 @@ public class Calendar: TemplatedControl
}
public static readonly StyledProperty FirstDayOfWeekProperty =
- AvaloniaProperty.Register(nameof(FirstDayOfWeek),
+ AvaloniaProperty.Register(nameof(FirstDayOfWeek),
defaultValue: DateTimeHelper.GetCurrentDateTimeFormatInfo().FirstDayOfWeek);
public DayOfWeek FirstDayOfWeek
{
@@ -53,7 +53,7 @@ public class Calendar: TemplatedControl
set => SetValue(FirstDayOfWeekProperty, value);
}
- public static readonly StyledProperty IsTodayHighlightedProperty = AvaloniaProperty.Register(nameof(IsTodayHighlighted), true);
+ public static readonly StyledProperty IsTodayHighlightedProperty = AvaloniaProperty.Register(nameof(IsTodayHighlighted), true);
public bool IsTodayHighlighted
{
get => GetValue(IsTodayHighlightedProperty);
@@ -61,7 +61,7 @@ public class Calendar: TemplatedControl
}
public static readonly StyledProperty?> BlackoutDatesProperty =
- AvaloniaProperty.Register?>(
+ AvaloniaProperty.Register?>(
nameof(BlackoutDates));
public AvaloniaList? BlackoutDates
@@ -70,7 +70,7 @@ public class Calendar: TemplatedControl
set => SetValue(BlackoutDatesProperty, value);
}
- public static readonly StyledProperty BlackoutDateRuleProperty = AvaloniaProperty.Register(
+ public static readonly StyledProperty BlackoutDateRuleProperty = AvaloniaProperty.Register(
nameof(BlackoutDateRule));
public IDateSelector? BlackoutDateRule
@@ -81,7 +81,7 @@ public class Calendar: TemplatedControl
private bool _isMonthMode = true;
- public static readonly DirectProperty IsMonthModeProperty = AvaloniaProperty.RegisterDirect(
+ public static readonly DirectProperty IsMonthModeProperty = AvaloniaProperty.RegisterDirect(
nameof(IsMonthMode), o => o.IsMonthMode, (o, v) => o.IsMonthMode = v);
public bool IsMonthMode
@@ -153,14 +153,14 @@ public class Calendar: TemplatedControl
{
SetCurrentValue(IsMonthModeProperty, false);
if (_yearView is null) return;
- _headerButton?.SetValue(Button.ContentProperty, _yearView.ContextDate.Year);
+ _headerButton?.SetValue(ContentControl.ContentProperty, _yearView.ContextDate.Year);
_yearView?.UpdateMode(CalendarYearViewMode.Month);
}
private void OnYearButtonClick(object sender, RoutedEventArgs e)
{
if (_yearView is null) return;
- _headerButton?.SetValue(Button.ContentProperty,
+ _headerButton?.SetValue(ContentControl.ContentProperty,
_yearView?.ContextDate.Year + "-" + (_yearView?.ContextDate.Year + 10));
_yearView?.UpdateMode(CalendarYearViewMode.Year);
SetCurrentValue(IsMonthModeProperty, false);
diff --git a/src/Ursa/Controls/DateTimePicker/CalendarMonthView.cs b/src/Ursa/Controls/DateTimePicker/CalendarMonthView.cs
index a1f46b0..a10fb28 100644
--- a/src/Ursa/Controls/DateTimePicker/CalendarMonthView.cs
+++ b/src/Ursa/Controls/DateTimePicker/CalendarMonthView.cs
@@ -9,7 +9,8 @@ using Avalonia.Layout;
namespace Ursa.Controls;
///
-/// Show days in a month.
+/// Show days in a month. CalendarMonthView itself doesn't handle any date range selection logic.
+/// it provides a method to mark preview range and selection range. The range limit may out of current displayed month.
///
[TemplatePart(PART_Grid, typeof(Grid))]
public class CalendarMonthView : TemplatedControl
@@ -32,7 +33,7 @@ public class CalendarMonthView : TemplatedControl
view.OnDayOfWeekChanged(args));
}
- internal Calendar? Owner { get; set; }
+ internal CalendarDisplayControl? Owner { get; set; }
///
/// The DateTime used to generate the month view. This date will be within the month.
@@ -156,6 +157,30 @@ public class CalendarMonthView : TemplatedControl
public event EventHandler? OnDateSelected;
public event EventHandler? OnDatePreviewed;
+ public void MarkDates(DateTime? startDate = null, DateTime? endDate = null, DateTime? previewStartDate = null, DateTime? previewEndDate = null)
+ {
+ if (_grid?.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 _grid.Children)
+ {
+ if (child is not CalendarDayButton { DataContext: DateTime d } button) continue;
+ if(d.Month != _contextDate.Month) continue;
+ button.ResetSelection();
+ 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;
+ }
+ }
+
+ [Obsolete]
public void MarkSelection(DateTime? start, DateTime? end)
{
if (_grid?.Children is null) return;
diff --git a/src/Ursa/Controls/DateTimePicker/CalendarYearButton.cs b/src/Ursa/Controls/DateTimePicker/CalendarYearButton.cs
index 9dc1b2f..bb0da21 100644
--- a/src/Ursa/Controls/DateTimePicker/CalendarYearButton.cs
+++ b/src/Ursa/Controls/DateTimePicker/CalendarYearButton.cs
@@ -12,39 +12,43 @@ internal enum CalendarYearViewMode
{
Month,
Year,
+
// The button represents 10 years.
- YearRange,
-}
+ YearRange
+}
[PseudoClasses(PC_Range, PseudoClassName.PC_Selected)]
-public class CalendarYearButton: ContentControl
+public class CalendarYearButton : ContentControl
{
public const string PC_Range = ":range";
+
+ public static readonly RoutedEvent ItemSelectedEvent =
+ RoutedEvent.Register(
+ nameof(ItemSelected), RoutingStrategies.Bubble);
+
static CalendarYearButton()
{
PressedMixin.Attach();
}
-
+
internal int Year { get; private set; }
-
+
internal int Month { get; private set; }
-
+
internal int StartYear { get; private set; }
-
+
internal int EndYear { get; private set; }
-
+
internal CalendarYearViewMode Mode { get; private set; }
-
- public static readonly RoutedEvent ItemSelectedEvent = RoutedEvent.Register(
- nameof(ItemSelected), RoutingStrategies.Bubble);
-
+
public event EventHandler ItemSelected
{
add => AddHandler(ItemSelectedEvent, value);
remove => RemoveHandler(ItemSelectedEvent, value);
}
- internal void SetValues(CalendarYearViewMode mode, DateTime contextDate, int? month = null, int? year = null, int? startYear = null, int? endYear = null)
+ internal void SetValues(CalendarYearViewMode mode, DateTime contextDate, int? month = null, int? year = null,
+ int? startYear = null, int? endYear = null)
{
Debug.Assert(!(month is null && year is null && startYear is null && endYear is null));
Mode = mode;
@@ -66,6 +70,5 @@ public class CalendarYearButton: ContentControl
base.OnPointerPressed(e);
RaiseEvent(new CalendarYearButtonEventArgs(Mode, Year, Month, StartYear, EndYear)
{ RoutedEvent = ItemSelectedEvent, Source = this });
-
}
}
\ No newline at end of file
diff --git a/src/Ursa/Controls/DateTimePicker/CalendarYearButtonEventArgs.cs b/src/Ursa/Controls/DateTimePicker/CalendarYearButtonEventArgs.cs
index fd0a545..4b49542 100644
--- a/src/Ursa/Controls/DateTimePicker/CalendarYearButtonEventArgs.cs
+++ b/src/Ursa/Controls/DateTimePicker/CalendarYearButtonEventArgs.cs
@@ -4,12 +4,14 @@ namespace Ursa.Controls;
public class CalendarYearButtonEventArgs: RoutedEventArgs
{
- internal int? Year { get; }
- internal int? Month { get; }
- internal int? StartYear { get; }
- internal int? EndYear { get; }
+ public int? Year { get; }
+ public int? Month { get; }
+ public int? StartYear { get; }
+ public int? EndYear { get; }
internal CalendarYearViewMode Mode { get; }
- internal CalendarYearButtonEventArgs( CalendarYearViewMode mode, int? year, int? month, int? startYear, int? endYear )
+
+ ///
+ internal CalendarYearButtonEventArgs(CalendarYearViewMode mode, int? year, int? month, int? startYear, int? endYear )
{
Year = year;
Month = month;
diff --git a/src/Ursa/Controls/DateTimePicker/DateTimeHelper.cs b/src/Ursa/Controls/DateTimePicker/DateTimeHelper.cs
index 498e6bd..5e10713 100644
--- a/src/Ursa/Controls/DateTimePicker/DateTimeHelper.cs
+++ b/src/Ursa/Controls/DateTimePicker/DateTimeHelper.cs
@@ -32,5 +32,14 @@ internal static class DateTimeHelper
{
return (dt1.Year - dt2.Year) * 12 + dt1.Month - dt2.Month;
}
-
+
+ public static DateTime Min(DateTime d1, DateTime d2)
+ {
+ return d1.Ticks > d2.Ticks ? d2 : d1;
+ }
+
+ public static DateTime Max(DateTime d1, DateTime d2)
+ {
+ return d1.Ticks < d2.Ticks ? d2 : d1;
+ }
}
\ No newline at end of file