feat: WIP.

This commit is contained in:
rabbitism
2024-06-18 00:36:55 +08:00
parent 1982f773ca
commit f75460a386
8 changed files with 165 additions and 92 deletions

View File

@@ -8,6 +8,6 @@
<StackPanel Margin="20" HorizontalAlignment="Left"> <StackPanel Margin="20" HorizontalAlignment="Left">
<u:CalendarMonthView /> <u:CalendarMonthView />
<u:CalendarYearView /> <u:CalendarYearView />
<u:Calendar/> <u:CalendarDisplayControl/>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

View File

@@ -5,7 +5,7 @@
<Design.PreviewWith> <Design.PreviewWith>
<StackPanel Margin="20" Spacing="5"> <StackPanel Margin="20" Spacing="5">
<u:CalendarMonthView /> <u:CalendarMonthView />
<u:Calendar /> <u:CalendarDisplayControl />
</StackPanel> </StackPanel>
</Design.PreviewWith> </Design.PreviewWith>
<!-- Add Resources Here --> <!-- Add Resources Here -->
@@ -120,15 +120,15 @@
</Style> </Style>
</ControlTheme> </ControlTheme>
<ControlTheme x:Key="{x:Type u:Calendar}" TargetType="u:Calendar"> <ControlTheme x:Key="{x:Type u:CalendarDisplayControl}" TargetType="u:CalendarDisplayControl">
<Setter Property="MinHeight" Value="300" /> <Setter Property="MinHeight" Value="300" />
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate TargetType="u:Calendar"> <ControlTemplate TargetType="u:CalendarDisplayControl">
<Panel> <Panel>
<Grid RowDefinitions="Auto, *"> <Grid RowDefinitions="Auto, *">
<Grid Grid.Row="0" ColumnDefinitions="Auto, Auto,*, Auto, Auto"> <Grid Grid.Row="0" ColumnDefinitions="Auto, Auto,*, Auto, Auto">
<Button <Button
Name="{x:Static u:Calendar.PART_PreviousYearButton}" Name="{x:Static u:CalendarDisplayControl.PART_PreviousYearButton}"
Grid.Column="0" Grid.Column="0"
HorizontalContentAlignment="Left" HorizontalContentAlignment="Left"
Foreground="{TemplateBinding Foreground}" Foreground="{TemplateBinding Foreground}"
@@ -141,7 +141,7 @@
</Button> </Button>
<Button <Button
Name="{x:Static u:Calendar.PART_PreviousButton}" Name="{x:Static u:CalendarDisplayControl.PART_PreviousButton}"
Grid.Column="1" Grid.Column="1"
HorizontalContentAlignment="Left" HorizontalContentAlignment="Left"
Foreground="{TemplateBinding Foreground}" Foreground="{TemplateBinding Foreground}"
@@ -155,7 +155,7 @@
<Grid Grid.Column="2" ColumnDefinitions="*, *"> <Grid Grid.Column="2" ColumnDefinitions="*, *">
<Button <Button
Name="{x:Static u:Calendar.PART_YearButton}" Name="{x:Static u:CalendarDisplayControl.PART_YearButton}"
Grid.Column="0" Grid.Column="0"
HorizontalContentAlignment="Center" HorizontalContentAlignment="Center"
Content="2024" Content="2024"
@@ -163,7 +163,7 @@
IsVisible="{TemplateBinding IsMonthMode}" IsVisible="{TemplateBinding IsMonthMode}"
Theme="{DynamicResource BorderlessButton}" /> Theme="{DynamicResource BorderlessButton}" />
<Button <Button
Name="{x:Static u:Calendar.PART_MonthButton}" Name="{x:Static u:CalendarDisplayControl.PART_MonthButton}"
Grid.Column="1" Grid.Column="1"
HorizontalContentAlignment="Center" HorizontalContentAlignment="Center"
Content="Apr" Content="Apr"
@@ -171,7 +171,7 @@
IsVisible="{TemplateBinding IsMonthMode}" IsVisible="{TemplateBinding IsMonthMode}"
Theme="{DynamicResource BorderlessButton}" /> Theme="{DynamicResource BorderlessButton}" />
<Button <Button
Name="{x:Static u:Calendar.PART_HeaderButton}" Name="{x:Static u:CalendarDisplayControl.PART_HeaderButton}"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="2" Grid.ColumnSpan="2"
IsVisible="{TemplateBinding IsMonthMode, Converter={x:Static BoolConverters.Not}}" IsVisible="{TemplateBinding IsMonthMode, Converter={x:Static BoolConverters.Not}}"
@@ -181,7 +181,7 @@
</Grid> </Grid>
<Button <Button
Name="{x:Static u:Calendar.PART_NextButton}" Name="{x:Static u:CalendarDisplayControl.PART_NextButton}"
Grid.Column="3" Grid.Column="3"
HorizontalContentAlignment="Left" HorizontalContentAlignment="Left"
Foreground="{TemplateBinding Foreground}" Foreground="{TemplateBinding Foreground}"
@@ -193,7 +193,7 @@
Foreground="{DynamicResource CalendarItemIconForeground}" /> Foreground="{DynamicResource CalendarItemIconForeground}" />
</Button> </Button>
<Button <Button
Name="{x:Static u:Calendar.PART_NextYearButton}" Name="{x:Static u:CalendarDisplayControl.PART_NextYearButton}"
Grid.Column="4" Grid.Column="4"
HorizontalContentAlignment="Left" HorizontalContentAlignment="Left"
Foreground="{TemplateBinding Foreground}" Foreground="{TemplateBinding Foreground}"
@@ -206,12 +206,12 @@
</Button> </Button>
</Grid> </Grid>
<u:CalendarMonthView <u:CalendarMonthView
Name="{x:Static u:Calendar.PART_MonthView}" Name="{x:Static u:CalendarDisplayControl.PART_MonthView}"
Grid.Row="1" Grid.Row="1"
VerticalAlignment="Top" VerticalAlignment="Top"
IsVisible="{TemplateBinding IsMonthMode}" /> IsVisible="{TemplateBinding IsMonthMode}" />
<u:CalendarYearView <u:CalendarYearView
Name="{x:Static u:Calendar.PART_YearView}" Name="{x:Static u:CalendarDisplayControl.PART_YearView}"
Grid.Row="1" Grid.Row="1"
Width="{Binding #PART_MonthView.Bounds.Width}" Width="{Binding #PART_MonthView.Bounds.Width}"
Height="{Binding #PART_MonthView.Bounds.Height}" Height="{Binding #PART_MonthView.Bounds.Height}"

View File

@@ -1,19 +1,17 @@
using Avalonia; using Avalonia.Controls;
using Avalonia.Controls;
using Avalonia.Controls.Metadata; using Avalonia.Controls.Metadata;
using Avalonia.Controls.Mixins; using Avalonia.Controls.Mixins;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Irihi.Avalonia.Shared.Common; using Irihi.Avalonia.Shared.Common;
using Irihi.Avalonia.Shared.Helpers;
using Ursa.EventArgs;
namespace Ursa.Controls; namespace Ursa.Controls;
[PseudoClasses(PseudoClassName.PC_Pressed, PseudoClassName.PC_Selected, [PseudoClasses(PseudoClassName.PC_Pressed, PseudoClassName.PC_Selected,
PC_StartDate, PC_EndDate, PC_PreviewStartDate, PC_PreviewEndDate, PC_InRange, PC_Today, PC_Blackout, PC_NotCurrentMonth)] PC_StartDate, PC_EndDate, PC_PreviewStartDate, PC_PreviewEndDate, PC_InRange, PC_Today, PC_Blackout,
public class CalendarDayButton: ContentControl PC_NotCurrentMonth)]
public class CalendarDayButton : ContentControl
{ {
public const string PC_StartDate = ":start-date"; public const string PC_StartDate = ":start-date";
public const string PC_EndDate = ":end-date"; public const string PC_EndDate = ":end-date";
@@ -24,9 +22,45 @@ public class CalendarDayButton: ContentControl
public const string PC_NotCurrentMonth = ":not-current-month"; public const string PC_NotCurrentMonth = ":not-current-month";
public const string PC_Blackout = ":blackout"; public const string PC_Blackout = ":blackout";
internal Calendar? Owner { get; set; } private static HashSet<string> _pseudoClasses =
[
PseudoClassName.PC_Selected, PC_EndDate, PC_PreviewStartDate,
PC_PreviewEndDate, PseudoClassName.PC_Selected, PC_InRange
];
public static readonly RoutedEvent<CalendarDayButtonEventArgs> DateSelectedEvent =
RoutedEvent.Register<CalendarDayButton, CalendarDayButtonEventArgs>(
nameof(DateSelected), RoutingStrategies.Bubble);
public static readonly RoutedEvent<CalendarDayButtonEventArgs> DatePreviewedEvent =
RoutedEvent.Register<CalendarDayButton, CalendarDayButtonEventArgs>(
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; private bool _isToday;
static CalendarDayButton()
{
PressedMixin.Attach<CalendarDayButton>();
}
// internal CalendarDisplayControl? Owner { get; set; }
public bool IsToday public bool IsToday
{ {
get => _isToday; get => _isToday;
@@ -37,29 +71,26 @@ public class CalendarDayButton: ContentControl
} }
} }
private bool _isStartDate;
public bool IsStartDate public bool IsStartDate
{ {
get => _isStartDate; get => _isStartDate;
set set
{ {
_isStartDate = value; _isStartDate = value;
PseudoClasses.Set(PC_StartDate, value); SetPseudoClass(PC_StartDate);
} }
} }
private bool _isEndDate;
public bool IsEndDate public bool IsEndDate
{ {
get => _isEndDate; get => _isEndDate;
set set
{ {
_isEndDate = value; _isEndDate = value;
PseudoClasses.Set(PC_EndDate, value); SetPseudoClass(PC_EndDate);
} }
} }
private bool _isPreviewStartDate;
public bool IsPreviewStartDate public bool IsPreviewStartDate
{ {
get => _isPreviewStartDate; get => _isPreviewStartDate;
@@ -70,7 +101,6 @@ public class CalendarDayButton: ContentControl
} }
} }
private bool _isPreviewEndDate;
public bool IsPreviewEndDate public bool IsPreviewEndDate
{ {
get => _isPreviewEndDate; get => _isPreviewEndDate;
@@ -81,7 +111,6 @@ public class CalendarDayButton: ContentControl
} }
} }
private bool _isInRange;
public bool IsInRange public bool IsInRange
{ {
get => _isInRange; get => _isInRange;
@@ -92,7 +121,6 @@ public class CalendarDayButton: ContentControl
} }
} }
private bool _isSelected;
public bool IsSelected public bool IsSelected
{ {
get => _isSelected; get => _isSelected;
@@ -103,7 +131,6 @@ public class CalendarDayButton: ContentControl
} }
} }
private bool _isBlackout;
/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
@@ -117,9 +144,9 @@ public class CalendarDayButton: ContentControl
} }
} }
private bool _isNotCurrentMonth;
/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
public bool IsNotCurrentMonth public bool IsNotCurrentMonth
{ {
@@ -131,32 +158,22 @@ public class CalendarDayButton: ContentControl
} }
} }
public static readonly RoutedEvent<CalendarDayButtonEventArgs> DateSelectedEvent = RoutedEvent.Register<CalendarDayButton, CalendarDayButtonEventArgs>(
nameof(DateSelected), RoutingStrategies.Bubble);
public event EventHandler<CalendarDayButtonEventArgs> DateSelected public event EventHandler<CalendarDayButtonEventArgs> DateSelected
{ {
add => AddHandler(DateSelectedEvent, value); add => AddHandler(DateSelectedEvent, value);
remove => RemoveHandler(DateSelectedEvent, value); remove => RemoveHandler(DateSelectedEvent, value);
} }
public static readonly RoutedEvent<CalendarDayButtonEventArgs> DatePreviewedEvent = RoutedEvent.Register<CalendarDayButton, CalendarDayButtonEventArgs>(
nameof(DatePreviewed), RoutingStrategies.Bubble);
public event EventHandler<CalendarDayButtonEventArgs> DatePreviewed public event EventHandler<CalendarDayButtonEventArgs> DatePreviewed
{ {
add => AddHandler(DateSelectedEvent, value); add => AddHandler(DateSelectedEvent, value);
remove => RemoveHandler(DateSelectedEvent, value); remove => RemoveHandler(DateSelectedEvent, value);
} }
static CalendarDayButton()
{
PressedMixin.Attach<CalendarDayButton>();
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e) protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{ {
base.OnApplyTemplate(e); base.OnApplyTemplate(e);
/*
PseudoClasses.Set(PC_Today, IsToday); PseudoClasses.Set(PC_Today, IsToday);
PseudoClasses.Set(PC_StartDate, IsStartDate); PseudoClasses.Set(PC_StartDate, IsStartDate);
PseudoClasses.Set(PC_EndDate, IsEndDate); PseudoClasses.Set(PC_EndDate, IsEndDate);
@@ -164,23 +181,40 @@ public class CalendarDayButton: ContentControl
PseudoClasses.Set(PC_PreviewEndDate, IsPreviewEndDate); PseudoClasses.Set(PC_PreviewEndDate, IsPreviewEndDate);
PseudoClasses.Set(PC_InRange, IsInRange); PseudoClasses.Set(PC_InRange, IsInRange);
PseudoClasses.Set(PseudoClassName.PC_Selected, IsSelected); PseudoClasses.Set(PseudoClassName.PC_Selected, IsSelected);
*/
} }
protected override void OnPointerPressed(PointerPressedEventArgs e) protected override void OnPointerPressed(PointerPressedEventArgs e)
{ {
base.OnPointerPressed(e); base.OnPointerPressed(e);
if (this.DataContext is DateTime d) if (DataContext is DateTime d)
{
RaiseEvent(new CalendarDayButtonEventArgs(d) { RoutedEvent = DateSelectedEvent, Source = this }); RaiseEvent(new CalendarDayButtonEventArgs(d) { RoutedEvent = DateSelectedEvent, Source = this });
} }
}
protected override void OnPointerEntered(PointerEventArgs e) protected override void OnPointerEntered(PointerEventArgs e)
{ {
base.OnPointerEntered(e); base.OnPointerEntered(e);
if (this.DataContext is DateTime d) if (DataContext is DateTime d)
{
RaiseEvent(new CalendarDayButtonEventArgs(d) { RoutedEvent = DateSelectedEvent, Source = this }); 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);
} }
} }

View File

@@ -17,7 +17,7 @@ namespace Ursa.Controls;
[TemplatePart(PART_HeaderButton, typeof(Button))] [TemplatePart(PART_HeaderButton, typeof(Button))]
[TemplatePart(PART_MonthView, typeof(CalendarMonthView))] [TemplatePart(PART_MonthView, typeof(CalendarMonthView))]
[TemplatePart(PART_YearView, typeof(CalendarYearView))] [TemplatePart(PART_YearView, typeof(CalendarYearView))]
public class Calendar: TemplatedControl public class CalendarDisplayControl: TemplatedControl
{ {
public const string PART_NextYearButton = "PART_NextYearButton"; public const string PART_NextYearButton = "PART_NextYearButton";
public const string PART_PreviousYearButton = "PART_PreviousYearButton"; public const string PART_PreviousYearButton = "PART_PreviousYearButton";
@@ -37,7 +37,7 @@ public class Calendar: TemplatedControl
private Button? _headerButton; private Button? _headerButton;
public static readonly StyledProperty<DateTime> SelectedDateProperty = AvaloniaProperty.Register<Calendar, DateTime>(nameof(SelectedDate), DateTime.Now); public static readonly StyledProperty<DateTime> SelectedDateProperty = AvaloniaProperty.Register<CalendarDisplayControl, DateTime>(nameof(SelectedDate), DateTime.Now);
public DateTime SelectedDate public DateTime SelectedDate
{ {
get => GetValue(SelectedDateProperty); get => GetValue(SelectedDateProperty);
@@ -45,7 +45,7 @@ public class Calendar: TemplatedControl
} }
public static readonly StyledProperty<DayOfWeek> FirstDayOfWeekProperty = public static readonly StyledProperty<DayOfWeek> FirstDayOfWeekProperty =
AvaloniaProperty.Register<Calendar, DayOfWeek>(nameof(FirstDayOfWeek), AvaloniaProperty.Register<CalendarDisplayControl, DayOfWeek>(nameof(FirstDayOfWeek),
defaultValue: DateTimeHelper.GetCurrentDateTimeFormatInfo().FirstDayOfWeek); defaultValue: DateTimeHelper.GetCurrentDateTimeFormatInfo().FirstDayOfWeek);
public DayOfWeek FirstDayOfWeek public DayOfWeek FirstDayOfWeek
{ {
@@ -53,7 +53,7 @@ public class Calendar: TemplatedControl
set => SetValue(FirstDayOfWeekProperty, value); set => SetValue(FirstDayOfWeekProperty, value);
} }
public static readonly StyledProperty<bool> IsTodayHighlightedProperty = AvaloniaProperty.Register<Calendar, bool>(nameof(IsTodayHighlighted), true); public static readonly StyledProperty<bool> IsTodayHighlightedProperty = AvaloniaProperty.Register<CalendarDisplayControl, bool>(nameof(IsTodayHighlighted), true);
public bool IsTodayHighlighted public bool IsTodayHighlighted
{ {
get => GetValue(IsTodayHighlightedProperty); get => GetValue(IsTodayHighlightedProperty);
@@ -61,7 +61,7 @@ public class Calendar: TemplatedControl
} }
public static readonly StyledProperty<AvaloniaList<DateRange>?> BlackoutDatesProperty = public static readonly StyledProperty<AvaloniaList<DateRange>?> BlackoutDatesProperty =
AvaloniaProperty.Register<Calendar, AvaloniaList<DateRange>?>( AvaloniaProperty.Register<CalendarDisplayControl, AvaloniaList<DateRange>?>(
nameof(BlackoutDates)); nameof(BlackoutDates));
public AvaloniaList<DateRange>? BlackoutDates public AvaloniaList<DateRange>? BlackoutDates
@@ -70,7 +70,7 @@ public class Calendar: TemplatedControl
set => SetValue(BlackoutDatesProperty, value); set => SetValue(BlackoutDatesProperty, value);
} }
public static readonly StyledProperty<IDateSelector?> BlackoutDateRuleProperty = AvaloniaProperty.Register<Calendar, IDateSelector?>( public static readonly StyledProperty<IDateSelector?> BlackoutDateRuleProperty = AvaloniaProperty.Register<CalendarDisplayControl, IDateSelector?>(
nameof(BlackoutDateRule)); nameof(BlackoutDateRule));
public IDateSelector? BlackoutDateRule public IDateSelector? BlackoutDateRule
@@ -81,7 +81,7 @@ public class Calendar: TemplatedControl
private bool _isMonthMode = true; private bool _isMonthMode = true;
public static readonly DirectProperty<Calendar, bool> IsMonthModeProperty = AvaloniaProperty.RegisterDirect<Calendar, bool>( public static readonly DirectProperty<CalendarDisplayControl, bool> IsMonthModeProperty = AvaloniaProperty.RegisterDirect<CalendarDisplayControl, bool>(
nameof(IsMonthMode), o => o.IsMonthMode, (o, v) => o.IsMonthMode = v); nameof(IsMonthMode), o => o.IsMonthMode, (o, v) => o.IsMonthMode = v);
public bool IsMonthMode public bool IsMonthMode
@@ -153,14 +153,14 @@ public class Calendar: TemplatedControl
{ {
SetCurrentValue(IsMonthModeProperty, false); SetCurrentValue(IsMonthModeProperty, false);
if (_yearView is null) return; if (_yearView is null) return;
_headerButton?.SetValue(Button.ContentProperty, _yearView.ContextDate.Year); _headerButton?.SetValue(ContentControl.ContentProperty, _yearView.ContextDate.Year);
_yearView?.UpdateMode(CalendarYearViewMode.Month); _yearView?.UpdateMode(CalendarYearViewMode.Month);
} }
private void OnYearButtonClick(object sender, RoutedEventArgs e) private void OnYearButtonClick(object sender, RoutedEventArgs e)
{ {
if (_yearView is null) return; if (_yearView is null) return;
_headerButton?.SetValue(Button.ContentProperty, _headerButton?.SetValue(ContentControl.ContentProperty,
_yearView?.ContextDate.Year + "-" + (_yearView?.ContextDate.Year + 10)); _yearView?.ContextDate.Year + "-" + (_yearView?.ContextDate.Year + 10));
_yearView?.UpdateMode(CalendarYearViewMode.Year); _yearView?.UpdateMode(CalendarYearViewMode.Year);
SetCurrentValue(IsMonthModeProperty, false); SetCurrentValue(IsMonthModeProperty, false);

View File

@@ -9,7 +9,8 @@ using Avalonia.Layout;
namespace Ursa.Controls; namespace Ursa.Controls;
/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
[TemplatePart(PART_Grid, typeof(Grid))] [TemplatePart(PART_Grid, typeof(Grid))]
public class CalendarMonthView : TemplatedControl public class CalendarMonthView : TemplatedControl
@@ -32,7 +33,7 @@ public class CalendarMonthView : TemplatedControl
view.OnDayOfWeekChanged(args)); view.OnDayOfWeekChanged(args));
} }
internal Calendar? Owner { get; set; } internal CalendarDisplayControl? Owner { get; set; }
/// <summary> /// <summary>
/// The DateTime used to generate the month view. This date will be within the month. /// 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<CalendarDayButtonEventArgs>? OnDateSelected; public event EventHandler<CalendarDayButtonEventArgs>? OnDateSelected;
public event EventHandler<CalendarDayButtonEventArgs>? OnDatePreviewed; public event EventHandler<CalendarDayButtonEventArgs>? 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) public void MarkSelection(DateTime? start, DateTime? end)
{ {
if (_grid?.Children is null) return; if (_grid?.Children is null) return;

View File

@@ -12,14 +12,20 @@ internal enum CalendarYearViewMode
{ {
Month, Month,
Year, Year,
// The button represents 10 years. // The button represents 10 years.
YearRange, YearRange
} }
[PseudoClasses(PC_Range, PseudoClassName.PC_Selected)] [PseudoClasses(PC_Range, PseudoClassName.PC_Selected)]
public class CalendarYearButton: ContentControl public class CalendarYearButton : ContentControl
{ {
public const string PC_Range = ":range"; public const string PC_Range = ":range";
public static readonly RoutedEvent<CalendarYearButtonEventArgs> ItemSelectedEvent =
RoutedEvent.Register<CalendarYearButton, CalendarYearButtonEventArgs>(
nameof(ItemSelected), RoutingStrategies.Bubble);
static CalendarYearButton() static CalendarYearButton()
{ {
PressedMixin.Attach<CalendarYearButton>(); PressedMixin.Attach<CalendarYearButton>();
@@ -35,16 +41,14 @@ public class CalendarYearButton: ContentControl
internal CalendarYearViewMode Mode { get; private set; } internal CalendarYearViewMode Mode { get; private set; }
public static readonly RoutedEvent<CalendarYearButtonEventArgs> ItemSelectedEvent = RoutedEvent.Register<CalendarYearButton, CalendarYearButtonEventArgs>(
nameof(ItemSelected), RoutingStrategies.Bubble);
public event EventHandler<CalendarDayButtonEventArgs> ItemSelected public event EventHandler<CalendarDayButtonEventArgs> ItemSelected
{ {
add => AddHandler(ItemSelectedEvent, value); add => AddHandler(ItemSelectedEvent, value);
remove => RemoveHandler(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)); Debug.Assert(!(month is null && year is null && startYear is null && endYear is null));
Mode = mode; Mode = mode;
@@ -66,6 +70,5 @@ public class CalendarYearButton: ContentControl
base.OnPointerPressed(e); base.OnPointerPressed(e);
RaiseEvent(new CalendarYearButtonEventArgs(Mode, Year, Month, StartYear, EndYear) RaiseEvent(new CalendarYearButtonEventArgs(Mode, Year, Month, StartYear, EndYear)
{ RoutedEvent = ItemSelectedEvent, Source = this }); { RoutedEvent = ItemSelectedEvent, Source = this });
} }
} }

View File

@@ -4,12 +4,14 @@ namespace Ursa.Controls;
public class CalendarYearButtonEventArgs: RoutedEventArgs public class CalendarYearButtonEventArgs: RoutedEventArgs
{ {
internal int? Year { get; } public int? Year { get; }
internal int? Month { get; } public int? Month { get; }
internal int? StartYear { get; } public int? StartYear { get; }
internal int? EndYear { get; } public int? EndYear { get; }
internal CalendarYearViewMode Mode { get; } internal CalendarYearViewMode Mode { get; }
internal CalendarYearButtonEventArgs( CalendarYearViewMode mode, int? year, int? month, int? startYear, int? endYear )
/// <inheritdoc />
internal CalendarYearButtonEventArgs(CalendarYearViewMode mode, int? year, int? month, int? startYear, int? endYear )
{ {
Year = year; Year = year;
Month = month; Month = month;

View File

@@ -33,4 +33,13 @@ internal static class DateTimeHelper
return (dt1.Year - dt2.Year) * 12 + dt1.Month - dt2.Month; 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;
}
} }