feat: WIP.
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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}"
|
||||||
|
|||||||
@@ -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";
|
||||||
@@ -23,10 +21,46 @@ public class CalendarDayButton: ContentControl
|
|||||||
public const string PC_Today = ":today";
|
public const string PC_Today = ":today";
|
||||||
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;
|
||||||
@@ -36,30 +70,27 @@ public class CalendarDayButton: ContentControl
|
|||||||
PseudoClasses.Set(PC_Today, value);
|
PseudoClasses.Set(PC_Today, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -69,8 +100,7 @@ public class CalendarDayButton: ContentControl
|
|||||||
PseudoClasses.Set(PC_PreviewStartDate, value);
|
PseudoClasses.Set(PC_PreviewStartDate, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool _isPreviewEndDate;
|
|
||||||
public bool IsPreviewEndDate
|
public bool IsPreviewEndDate
|
||||||
{
|
{
|
||||||
get => _isPreviewEndDate;
|
get => _isPreviewEndDate;
|
||||||
@@ -80,8 +110,7 @@ public class CalendarDayButton: ContentControl
|
|||||||
PseudoClasses.Set(PC_PreviewEndDate, value);
|
PseudoClasses.Set(PC_PreviewEndDate, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -102,10 +130,9 @@ public class CalendarDayButton: ContentControl
|
|||||||
PseudoClasses.Set(PseudoClassName.PC_Selected, value);
|
PseudoClasses.Set(PseudoClassName.PC_Selected, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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>
|
||||||
public bool IsBlackout
|
public bool IsBlackout
|
||||||
{
|
{
|
||||||
@@ -116,10 +143,10 @@ public class CalendarDayButton: ContentControl
|
|||||||
PseudoClasses.Set(PC_Blackout, value);
|
PseudoClasses.Set(PC_Blackout, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
{
|
{
|
||||||
@@ -130,33 +157,23 @@ public class CalendarDayButton: ContentControl
|
|||||||
PseudoClasses.Set(PC_NotCurrentMonth, value);
|
PseudoClasses.Set(PC_NotCurrentMonth, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -12,39 +12,43 @@ 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>();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal int Year { get; private set; }
|
internal int Year { get; private set; }
|
||||||
|
|
||||||
internal int Month { get; private set; }
|
internal int Month { get; private set; }
|
||||||
|
|
||||||
internal int StartYear { get; private set; }
|
internal int StartYear { get; private set; }
|
||||||
|
|
||||||
internal int EndYear { get; private set; }
|
internal int EndYear { get; private set; }
|
||||||
|
|
||||||
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 });
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -32,5 +32,14 @@ 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user