feat: WIP.
This commit is contained in:
@@ -6,8 +6,6 @@
|
|||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Ursa.Demo.Pages.DatePickerDemo">
|
x:Class="Ursa.Demo.Pages.DatePickerDemo">
|
||||||
<StackPanel Margin="20" HorizontalAlignment="Left">
|
<StackPanel Margin="20" HorizontalAlignment="Left">
|
||||||
<u:CalendarMonthView />
|
|
||||||
<u:CalendarYearView />
|
|
||||||
<u:CalendarView/>
|
<u:CalendarView/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
xmlns:u="https://irihi.tech/ursa">
|
xmlns:u="https://irihi.tech/ursa">
|
||||||
<Design.PreviewWith>
|
<Design.PreviewWith>
|
||||||
<StackPanel Margin="20" Spacing="5">
|
<StackPanel Margin="20" Spacing="5">
|
||||||
<u:CalendarMonthView />
|
|
||||||
<u:CalendarView />
|
<u:CalendarView />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Design.PreviewWith>
|
</Design.PreviewWith>
|
||||||
@@ -119,144 +118,6 @@
|
|||||||
<Setter Property="Cursor" Value="No" />
|
<Setter Property="Cursor" Value="No" />
|
||||||
</Style>
|
</Style>
|
||||||
</ControlTheme>
|
</ControlTheme>
|
||||||
|
|
||||||
<ControlTheme x:Key="{x:Type u:CalendarView}" TargetType="u:CalendarView">
|
|
||||||
<Setter Property="MinHeight" Value="300" />
|
|
||||||
<Setter Property="Template">
|
|
||||||
<ControlTemplate TargetType="u:CalendarView">
|
|
||||||
<Panel>
|
|
||||||
<Grid RowDefinitions="Auto, *">
|
|
||||||
<Grid Grid.Row="0" ColumnDefinitions="Auto, Auto,*, Auto, Auto">
|
|
||||||
<Button
|
|
||||||
Name="{x:Static u:CalendarView.PART_PreviousYearButton}"
|
|
||||||
Grid.Column="0"
|
|
||||||
HorizontalContentAlignment="Left"
|
|
||||||
Foreground="{TemplateBinding Foreground}"
|
|
||||||
Theme="{DynamicResource BorderlessButton}">
|
|
||||||
<PathIcon
|
|
||||||
Width="12"
|
|
||||||
Height="12"
|
|
||||||
Data="{DynamicResource CalendarItemPreviousIconGlyph}"
|
|
||||||
Foreground="{DynamicResource CalendarItemIconForeground}" />
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
Name="{x:Static u:CalendarView.PART_PreviousButton}"
|
|
||||||
Grid.Column="1"
|
|
||||||
HorizontalContentAlignment="Left"
|
|
||||||
Foreground="{TemplateBinding Foreground}"
|
|
||||||
Theme="{DynamicResource BorderlessButton}">
|
|
||||||
<PathIcon
|
|
||||||
Width="12"
|
|
||||||
Height="12"
|
|
||||||
Data="{DynamicResource CalendarItemPreviousIconGlyph}"
|
|
||||||
Foreground="{DynamicResource CalendarItemIconForeground}" />
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Grid Grid.Column="2" ColumnDefinitions="*, *">
|
|
||||||
<Button
|
|
||||||
Name="{x:Static u:CalendarView.PART_YearButton}"
|
|
||||||
Grid.Column="0"
|
|
||||||
HorizontalContentAlignment="Center"
|
|
||||||
Content="2024"
|
|
||||||
Foreground="{TemplateBinding Foreground}"
|
|
||||||
IsVisible="{TemplateBinding IsMonthMode}"
|
|
||||||
Theme="{DynamicResource BorderlessButton}" />
|
|
||||||
<Button
|
|
||||||
Name="{x:Static u:CalendarView.PART_MonthButton}"
|
|
||||||
Grid.Column="1"
|
|
||||||
HorizontalContentAlignment="Center"
|
|
||||||
Content="Apr"
|
|
||||||
Foreground="{TemplateBinding Foreground}"
|
|
||||||
IsVisible="{TemplateBinding IsMonthMode}"
|
|
||||||
Theme="{DynamicResource BorderlessButton}" />
|
|
||||||
<Button
|
|
||||||
Name="{x:Static u:CalendarView.PART_HeaderButton}"
|
|
||||||
Grid.Column="0"
|
|
||||||
Grid.ColumnSpan="2"
|
|
||||||
IsVisible="{TemplateBinding IsMonthMode, Converter={x:Static BoolConverters.Not}}"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
HorizontalContentAlignment="Center"
|
|
||||||
Content="2020-2030" />
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
Name="{x:Static u:CalendarView.PART_NextButton}"
|
|
||||||
Grid.Column="3"
|
|
||||||
HorizontalContentAlignment="Left"
|
|
||||||
Foreground="{TemplateBinding Foreground}"
|
|
||||||
Theme="{DynamicResource BorderlessButton}">
|
|
||||||
<PathIcon
|
|
||||||
Width="12"
|
|
||||||
Height="12"
|
|
||||||
Data="{DynamicResource CalendarItemNextIconGlyph}"
|
|
||||||
Foreground="{DynamicResource CalendarItemIconForeground}" />
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
Name="{x:Static u:CalendarView.PART_NextYearButton}"
|
|
||||||
Grid.Column="4"
|
|
||||||
HorizontalContentAlignment="Left"
|
|
||||||
Foreground="{TemplateBinding Foreground}"
|
|
||||||
Theme="{DynamicResource BorderlessButton}">
|
|
||||||
<PathIcon
|
|
||||||
Width="12"
|
|
||||||
Height="12"
|
|
||||||
Data="{DynamicResource CalendarItemNextIconGlyph}"
|
|
||||||
Foreground="{DynamicResource CalendarItemIconForeground}" />
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
<u:CalendarMonthView
|
|
||||||
Name="{x:Static u:CalendarView.PART_MonthView}"
|
|
||||||
Grid.Row="1"
|
|
||||||
VerticalAlignment="Top"
|
|
||||||
IsVisible="{TemplateBinding IsMonthMode}" />
|
|
||||||
<u:CalendarYearView
|
|
||||||
Name="{x:Static u:CalendarView.PART_YearView}"
|
|
||||||
Grid.Row="1"
|
|
||||||
Width="{Binding #PART_MonthView.Bounds.Width}"
|
|
||||||
Height="{Binding #PART_MonthView.Bounds.Height}"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
IsVisible="{TemplateBinding IsMonthMode,
|
|
||||||
Converter={x:Static BoolConverters.Not}}" />
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
</Panel>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter>
|
|
||||||
</ControlTheme>
|
|
||||||
|
|
||||||
<ControlTheme x:Key="{x:Type u:CalendarMonthView}" TargetType="u:CalendarMonthView">
|
|
||||||
<Setter Property="Template">
|
|
||||||
<ControlTemplate>
|
|
||||||
<Grid
|
|
||||||
Name="{x:Static u:CalendarMonthView.PART_Grid}"
|
|
||||||
ColumnDefinitions="*, *, *, *, *, *, *"
|
|
||||||
RowDefinitions="*, Auto, *, *, *, *, *, *">
|
|
||||||
<Rectangle
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.Column="0"
|
|
||||||
Grid.ColumnSpan="7"
|
|
||||||
Height="1"
|
|
||||||
Margin="8,8,8,0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Fill="{DynamicResource SemiGrey2}" />
|
|
||||||
</Grid>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter>
|
|
||||||
</ControlTheme>
|
|
||||||
|
|
||||||
<ControlTheme x:Key="{x:Type u:CalendarYearView}" TargetType="u:CalendarYearView">
|
|
||||||
<Setter Property="Template">
|
|
||||||
<ControlTemplate>
|
|
||||||
<Grid
|
|
||||||
Name="{x:Static u:CalendarYearView.PART_Grid}"
|
|
||||||
ColumnDefinitions="*, *, *"
|
|
||||||
RowDefinitions="*, *, *, *" />
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter>
|
|
||||||
</ControlTheme>
|
|
||||||
|
|
||||||
<ControlTheme x:Key="{x:Type u:CalendarYearButton}" TargetType="u:CalendarYearButton">
|
<ControlTheme x:Key="{x:Type u:CalendarYearButton}" TargetType="u:CalendarYearButton">
|
||||||
<Setter Property="MinWidth" Value="32" />
|
<Setter Property="MinWidth" Value="32" />
|
||||||
<Setter Property="MinHeight" Value="32" />
|
<Setter Property="MinHeight" Value="32" />
|
||||||
@@ -298,4 +159,119 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</Style>
|
</Style>
|
||||||
</ControlTheme>
|
</ControlTheme>
|
||||||
|
<ControlTheme x:Key="{x:Type u:CalendarView}" TargetType="u:CalendarView">
|
||||||
|
<Setter Property="MinHeight" Value="300" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<ControlTemplate TargetType="u:CalendarView">
|
||||||
|
<Panel>
|
||||||
|
<Grid RowDefinitions="Auto, *">
|
||||||
|
<Grid Grid.Row="0" ColumnDefinitions="Auto, Auto,*, Auto, Auto">
|
||||||
|
<Button
|
||||||
|
Name="{x:Static u:CalendarView.PART_PreviousYearButton}"
|
||||||
|
Grid.Column="0"
|
||||||
|
HorizontalContentAlignment="Left"
|
||||||
|
Foreground="{TemplateBinding Foreground}"
|
||||||
|
Theme="{DynamicResource BorderlessButton}">
|
||||||
|
<PathIcon
|
||||||
|
Width="12"
|
||||||
|
Height="12"
|
||||||
|
Data="{DynamicResource CalendarItemPreviousIconGlyph}"
|
||||||
|
Foreground="{DynamicResource CalendarItemIconForeground}" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
Name="{x:Static u:CalendarView.PART_PreviousButton}"
|
||||||
|
Grid.Column="1"
|
||||||
|
HorizontalContentAlignment="Left"
|
||||||
|
Foreground="{TemplateBinding Foreground}"
|
||||||
|
Theme="{DynamicResource BorderlessButton}">
|
||||||
|
<PathIcon
|
||||||
|
Width="12"
|
||||||
|
Height="12"
|
||||||
|
Data="{DynamicResource CalendarItemPreviousIconGlyph}"
|
||||||
|
Foreground="{DynamicResource CalendarItemIconForeground}" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Grid Grid.Column="2" ColumnDefinitions="*, *">
|
||||||
|
<Button
|
||||||
|
Name="{x:Static u:CalendarView.PART_YearButton}"
|
||||||
|
Grid.Column="0"
|
||||||
|
HorizontalContentAlignment="Center"
|
||||||
|
Foreground="{TemplateBinding Foreground}"
|
||||||
|
Theme="{DynamicResource BorderlessButton}" />
|
||||||
|
<Button
|
||||||
|
Name="{x:Static u:CalendarView.PART_MonthButton}"
|
||||||
|
Grid.Column="1"
|
||||||
|
HorizontalContentAlignment="Center"
|
||||||
|
Foreground="{TemplateBinding Foreground}"
|
||||||
|
Theme="{DynamicResource BorderlessButton}" />
|
||||||
|
<Button
|
||||||
|
Name="{x:Static u:CalendarView.PART_HeaderButton}"
|
||||||
|
Grid.Column="0"
|
||||||
|
IsVisible="True"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Center" />
|
||||||
|
</Grid>
|
||||||
|
<Button
|
||||||
|
Name="{x:Static u:CalendarView.PART_NextButton}"
|
||||||
|
Grid.Column="3"
|
||||||
|
HorizontalContentAlignment="Left"
|
||||||
|
Foreground="{TemplateBinding Foreground}"
|
||||||
|
Theme="{DynamicResource BorderlessButton}">
|
||||||
|
<PathIcon
|
||||||
|
Width="12"
|
||||||
|
Height="12"
|
||||||
|
Data="{DynamicResource CalendarItemNextIconGlyph}"
|
||||||
|
Foreground="{DynamicResource CalendarItemIconForeground}" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
Name="{x:Static u:CalendarView.PART_NextYearButton}"
|
||||||
|
Grid.Column="4"
|
||||||
|
HorizontalContentAlignment="Left"
|
||||||
|
Foreground="{TemplateBinding Foreground}"
|
||||||
|
Theme="{DynamicResource BorderlessButton}">
|
||||||
|
<PathIcon
|
||||||
|
Width="12"
|
||||||
|
Height="12"
|
||||||
|
Data="{DynamicResource CalendarItemNextIconGlyph}"
|
||||||
|
Foreground="{DynamicResource CalendarItemIconForeground}" />
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
<Grid
|
||||||
|
Name="{x:Static u:CalendarView.PART_MonthGrid}"
|
||||||
|
Grid.Row="1"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
ColumnDefinitions="*, *, *, *, *, *, *"
|
||||||
|
RowDefinitions="*, Auto, *, *, *, *, *, *" />
|
||||||
|
<Grid
|
||||||
|
Name="{x:Static u:CalendarView.PART_YearGrid}"
|
||||||
|
Grid.Row="1"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
ColumnDefinitions="*, *, *"
|
||||||
|
RowDefinitions="*, *, *, *" />
|
||||||
|
</Grid>
|
||||||
|
</Panel>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter>
|
||||||
|
<Style Selector="^:month">
|
||||||
|
<Style Selector="^ /template/ Button#PART_YearButton, ^ /template/ Button#PART_MonthButton,^ /template/ Grid#PART_MonthGrid">
|
||||||
|
<Setter Property="Control.IsVisible" Value="True" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="^ /template/ Button#PART_HeaderButton, ^ /template/ Grid#PART_YearGrid">
|
||||||
|
<Setter Property="Control.IsVisible" Value="False" />
|
||||||
|
</Style>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="^:not(:month)">
|
||||||
|
<Style Selector="^ /template/ Button#PART_YearButton, ^ /template/ Button#PART_MonthButton,^ /template/ Grid#PART_MonthGrid">
|
||||||
|
<Setter Property="Control.IsVisible" Value="False" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="^ /template/ Button#PART_HeaderButton, ^ /template/ Grid#PART_YearGrid">
|
||||||
|
<Setter Property="Control.IsVisible" Value="True" />
|
||||||
|
</Style>
|
||||||
|
</Style>
|
||||||
|
</ControlTheme>
|
||||||
|
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using Avalonia.Layout;
|
|||||||
|
|
||||||
namespace Ursa.Controls;
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
|
/*
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Show days in a month. CalendarMonthView itself doesn't handle any date range selection logic.
|
/// 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.
|
/// it provides a method to mark preview range and selection range. The range limit may out of current displayed month.
|
||||||
@@ -227,3 +228,5 @@ public class CalendarMonthView : TemplatedControl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
using System.Globalization;
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Globalization;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Collections;
|
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.Metadata;
|
using Avalonia.Controls.Metadata;
|
||||||
using Avalonia.Controls.Primitives;
|
using Avalonia.Controls.Primitives;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Layout;
|
using Avalonia.Layout;
|
||||||
using Avalonia.Media.TextFormatting;
|
|
||||||
using Irihi.Avalonia.Shared.Helpers;
|
using Irihi.Avalonia.Shared.Helpers;
|
||||||
|
using Calendar = System.Globalization.Calendar;
|
||||||
|
|
||||||
namespace Ursa.Controls;
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
@@ -19,11 +18,10 @@ namespace Ursa.Controls;
|
|||||||
[TemplatePart(PART_YearButton, typeof(Button))]
|
[TemplatePart(PART_YearButton, typeof(Button))]
|
||||||
[TemplatePart(PART_MonthButton, typeof(Button))]
|
[TemplatePart(PART_MonthButton, typeof(Button))]
|
||||||
[TemplatePart(PART_HeaderButton, typeof(Button))]
|
[TemplatePart(PART_HeaderButton, typeof(Button))]
|
||||||
[TemplatePart(PART_MonthView, typeof(CalendarMonthView))]
|
|
||||||
[TemplatePart(PART_YearView, typeof(CalendarYearView))]
|
|
||||||
[TemplatePart(PART_MonthGrid, typeof(Grid))]
|
[TemplatePart(PART_MonthGrid, typeof(Grid))]
|
||||||
[TemplatePart(PART_YearGrid, typeof(Grid))]
|
[TemplatePart(PART_YearGrid, typeof(Grid))]
|
||||||
public class CalendarView: TemplatedControl
|
[PseudoClasses(PC_Month)]
|
||||||
|
public class CalendarView : 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";
|
||||||
@@ -31,51 +29,79 @@ public class CalendarView: TemplatedControl
|
|||||||
public const string PART_PreviousButton = "PART_PreviousButton";
|
public const string PART_PreviousButton = "PART_PreviousButton";
|
||||||
public const string PART_YearButton = "PART_YearButton";
|
public const string PART_YearButton = "PART_YearButton";
|
||||||
public const string PART_MonthButton = "PART_MonthButton";
|
public const string PART_MonthButton = "PART_MonthButton";
|
||||||
public const string PART_MonthView = "PART_MonthView";
|
|
||||||
public const string PART_YearView = "PART_YearView";
|
|
||||||
public const string PART_HeaderButton = "PART_HeaderButton";
|
public const string PART_HeaderButton = "PART_HeaderButton";
|
||||||
public const string PART_MonthGrid = "PART_MonthGrid";
|
public const string PART_MonthGrid = "PART_MonthGrid";
|
||||||
public const string PART_YearGrid = "PART_YearGried";
|
public const string PART_YearGrid = "PART_YearGrid";
|
||||||
|
public const string PC_Month = ":month";
|
||||||
|
|
||||||
private const string ShortestDayName = "ShortestDayName";
|
private const string ShortestDayName = "ShortestDayName";
|
||||||
|
|
||||||
private readonly System.Globalization.Calendar _calendar = new GregorianCalendar();
|
internal static readonly DirectProperty<CalendarView, CalendarViewMode> ModeProperty =
|
||||||
|
AvaloniaProperty.RegisterDirect<CalendarView, CalendarViewMode>(
|
||||||
internal CalendarViewMode Mode;
|
nameof(Mode), o => o.Mode, (o, v) => o.Mode = v, unsetValue: CalendarViewMode.Month);
|
||||||
|
|
||||||
//private CalendarMonthView? _monthView;
|
|
||||||
//private CalendarYearView? _yearView;
|
|
||||||
private Grid? _monthGrid;
|
|
||||||
private Grid? _yearGrid;
|
|
||||||
// Year button only shows the year in month mode.
|
|
||||||
private Button? _yearButton;
|
|
||||||
// Month button only shows the month in month mode.
|
|
||||||
private Button? _monthButton;
|
|
||||||
// Header button shows year in year mode, and year range in higher mode.
|
|
||||||
private Button? _headerButton;
|
|
||||||
|
|
||||||
public DateContext ContextDate { get; set; } = new DateContext();
|
|
||||||
|
|
||||||
public event EventHandler<CalendarDayButtonEventArgs>? OnDateSelected;
|
|
||||||
public event EventHandler<CalendarDayButtonEventArgs>? OnDatePreviewed;
|
|
||||||
|
|
||||||
public static readonly StyledProperty<bool> IsTodayHighlightedProperty =
|
public static readonly StyledProperty<bool> IsTodayHighlightedProperty =
|
||||||
DatePickerBase.IsTodayHighlightedProperty.AddOwner<CalendarView>();
|
DatePickerBase.IsTodayHighlightedProperty.AddOwner<CalendarView>();
|
||||||
|
|
||||||
|
public static readonly StyledProperty<DayOfWeek> FirstDayOfWeekProperty =
|
||||||
|
DatePickerBase.FirstDayOfWeekProperty.AddOwner<CalendarView>();
|
||||||
|
|
||||||
|
private readonly Calendar _calendar = new GregorianCalendar();
|
||||||
|
|
||||||
|
// Header button shows year in year mode, and year range in higher mode.
|
||||||
|
private Button? _headerButton;
|
||||||
|
|
||||||
|
private CalendarViewMode _mode;
|
||||||
|
|
||||||
|
// Month button only shows the month in month mode.
|
||||||
|
private Button? _monthButton;
|
||||||
|
|
||||||
|
private Grid? _monthGrid;
|
||||||
|
|
||||||
|
// Year button only shows the year in month mode.
|
||||||
|
private Button? _yearButton;
|
||||||
|
private Grid? _yearGrid;
|
||||||
|
|
||||||
|
static CalendarView()
|
||||||
|
{
|
||||||
|
FirstDayOfWeekProperty.Changed.AddClassHandler<CalendarView, DayOfWeek>((view, args) =>
|
||||||
|
view.OnFirstDayOfWeekChanged(args));
|
||||||
|
ModeProperty.Changed.AddClassHandler<CalendarView, CalendarViewMode>((view, args) =>
|
||||||
|
{
|
||||||
|
view.PseudoClasses.Set(PC_Month, args.NewValue.Value == CalendarViewMode.Month);
|
||||||
|
Debug.WriteLine(args.NewValue.Value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
internal CalendarViewMode Mode
|
||||||
|
{
|
||||||
|
get => _mode;
|
||||||
|
set => SetAndRaise(ModeProperty, ref _mode, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateContext ContextDate { get; set; } = new();
|
||||||
|
|
||||||
public bool IsTodayHighlighted
|
public bool IsTodayHighlighted
|
||||||
{
|
{
|
||||||
get => GetValue(IsTodayHighlightedProperty);
|
get => GetValue(IsTodayHighlightedProperty);
|
||||||
set => SetValue(IsTodayHighlightedProperty, value);
|
set => SetValue(IsTodayHighlightedProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly StyledProperty<DayOfWeek> FirstDayOfWeekProperty =
|
|
||||||
DatePickerBase.FirstDayOfWeekProperty.AddOwner<CalendarView>();
|
|
||||||
|
|
||||||
public DayOfWeek FirstDayOfWeek
|
public DayOfWeek FirstDayOfWeek
|
||||||
{
|
{
|
||||||
get => GetValue(FirstDayOfWeekProperty);
|
get => GetValue(FirstDayOfWeekProperty);
|
||||||
set => SetValue(FirstDayOfWeekProperty, value);
|
set => SetValue(FirstDayOfWeekProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public event EventHandler<CalendarDayButtonEventArgs>? OnDateSelected;
|
||||||
|
public event EventHandler<CalendarDayButtonEventArgs>? OnDatePreviewed;
|
||||||
|
|
||||||
|
private void OnFirstDayOfWeekChanged(AvaloniaPropertyChangedEventArgs<DayOfWeek> args)
|
||||||
|
{
|
||||||
|
UpdateMonthViewHeader(args.NewValue.Value);
|
||||||
|
RefreshDayButtons();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnApplyTemplate(e);
|
base.OnApplyTemplate(e);
|
||||||
@@ -94,30 +120,40 @@ public class CalendarView: TemplatedControl
|
|||||||
Button.ClickEvent.AddHandler(OnHeaderMonthButtonClick, _monthButton);
|
Button.ClickEvent.AddHandler(OnHeaderMonthButtonClick, _monthButton);
|
||||||
Button.ClickEvent.AddHandler(OnHeaderButtonClick, _headerButton);
|
Button.ClickEvent.AddHandler(OnHeaderButtonClick, _headerButton);
|
||||||
|
|
||||||
|
ContextDate = new DateContext(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day);
|
||||||
|
PseudoClasses.Set(PC_Month, Mode == CalendarViewMode.Month);
|
||||||
GenerateGridElements();
|
GenerateGridElements();
|
||||||
|
RefreshDayButtons();
|
||||||
|
RefreshYearButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rule:
|
/// Rule:
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sender"></param>
|
/// <param name="sender"></param>
|
||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
private void OnHeaderButtonClick(object sender, RoutedEventArgs e)
|
private void OnHeaderButtonClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (Mode == CalendarViewMode.Month)
|
// Header button should be hidden in Month mode.
|
||||||
{
|
if (Mode == CalendarViewMode.Month) return;
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Mode == CalendarViewMode.Year)
|
if (Mode == CalendarViewMode.Year)
|
||||||
{
|
{
|
||||||
|
Mode = CalendarViewMode.Decade;
|
||||||
|
RefreshYearButtons();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if(Mode == CalendarViewMode.Decade)
|
||||||
|
{
|
||||||
|
Mode = CalendarViewMode.Century;
|
||||||
|
RefreshYearButtons();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Mode == CalendarViewMode.Century) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate Buttons and labels for MonthView.
|
/// Generate Buttons and labels for MonthView.
|
||||||
/// Generate Buttons for YearView.
|
/// Generate Buttons for YearView.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void GenerateGridElements()
|
private void GenerateGridElements()
|
||||||
{
|
{
|
||||||
@@ -147,6 +183,7 @@ public class CalendarView: TemplatedControl
|
|||||||
cell.AddHandler(CalendarDayButton.DatePreviewedEvent, OnCellDatePreviewed);
|
cell.AddHandler(CalendarDayButton.DatePreviewedEvent, OnCellDatePreviewed);
|
||||||
children.Add(cell);
|
children.Add(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
_monthGrid?.Children.AddRange(children);
|
_monthGrid?.Children.AddRange(children);
|
||||||
|
|
||||||
// Generate month/year buttons.
|
// Generate month/year buttons.
|
||||||
@@ -160,14 +197,16 @@ public class CalendarView: TemplatedControl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RefreshButtons(DateTime date)
|
private void RefreshDayButtons()
|
||||||
{
|
{
|
||||||
if (_monthGrid is null) return;
|
if (_monthGrid is null) return;
|
||||||
var children = _monthGrid.Children;
|
var children = _monthGrid.Children;
|
||||||
var info = DateTimeHelper.GetCurrentDateTimeFormatInfo();
|
var info = DateTimeHelper.GetCurrentDateTimeFormatInfo();
|
||||||
var dayBefore = PreviousMonthDays(date);
|
var date = new DateTime(ContextDate.Year.Value, ContextDate.Month.Value, ContextDate.Day.Value);
|
||||||
|
var dayBefore =
|
||||||
|
PreviousMonthDays(date);
|
||||||
var dateToSet = date.GetFirstDayOfMonth().AddDays(-dayBefore);
|
var dateToSet = date.GetFirstDayOfMonth().AddDays(-dayBefore);
|
||||||
for (var i = 8; i < children.Count; i++)
|
for (var i = 7; i < children.Count; i++)
|
||||||
{
|
{
|
||||||
var day = dateToSet;
|
var day = dateToSet;
|
||||||
var cell = children[i] as CalendarDayButton;
|
var cell = children[i] as CalendarDayButton;
|
||||||
@@ -181,15 +220,57 @@ public class CalendarView: TemplatedControl
|
|||||||
FadeOutDayButtons();
|
FadeOutDayButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RefreshYearButtons()
|
||||||
|
{
|
||||||
|
if (_yearGrid is null) return;
|
||||||
|
var mode = Mode;
|
||||||
|
var contextDate = ContextDate;
|
||||||
|
for (var i = 0; i < 12; i++)
|
||||||
|
{
|
||||||
|
var child = _yearGrid.Children[i] as CalendarYearButton;
|
||||||
|
if (child is null) continue;
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case CalendarViewMode.Month:
|
||||||
|
child.SetValues(CalendarViewMode.Year, i);
|
||||||
|
break;
|
||||||
|
case CalendarViewMode.Year:
|
||||||
|
child.SetValues(CalendarViewMode.Decade, year: ContextDate.Year / 10 * 10 + i - 1);
|
||||||
|
break;
|
||||||
|
case CalendarViewMode.Decade:
|
||||||
|
var startYear = (ContextDate.Year / 10 + i - 1) * 10;
|
||||||
|
var endYear = (ContextDate.Year / 10 + i - 1) * 10 + 10;
|
||||||
|
child.SetValues(CalendarViewMode.Century, startYear: startYear, endYear: endYear);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void FadeOutDayButtons()
|
private void FadeOutDayButtons()
|
||||||
{
|
{
|
||||||
if (_monthGrid is null) return;
|
if (_monthGrid is null) return;
|
||||||
var children = _monthGrid.Children;
|
var children = _monthGrid.Children;
|
||||||
for (var i = 8; i < children.Count; i++)
|
for (var i = 7; i < children.Count; i++)
|
||||||
if (children[i] is CalendarDayButton { DataContext: DateTime d } button && d.Month != ContextDate.Month)
|
if (children[i] is CalendarDayButton { DataContext: DateTime d } button && d.Month != ContextDate.Month)
|
||||||
button.IsNotCurrentMonth = true;
|
button.IsNotCurrentMonth = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateMonthViewHeader(DayOfWeek day)
|
||||||
|
{
|
||||||
|
var dayOfWeek = (int)day;
|
||||||
|
var info = DateTimeHelper.GetCurrentDateTimeFormatInfo();
|
||||||
|
var texts = _monthGrid?.Children.Where(a => a is TextBlock { Tag: ShortestDayName }).ToList();
|
||||||
|
if (texts is not null)
|
||||||
|
for (var i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
var d = (dayOfWeek + i) % DateTimeHelper.NumberOfDaysPerWeek;
|
||||||
|
texts[i].SetValue(TextBlock.TextProperty, info.ShortestDayNames[d]);
|
||||||
|
texts[i].SetValue(HorizontalAlignmentProperty, HorizontalAlignment.Center);
|
||||||
|
texts[i].SetValue(Grid.RowProperty, 0);
|
||||||
|
texts[i].SetValue(Grid.ColumnProperty, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int PreviousMonthDays(DateTime date)
|
private int PreviousMonthDays(DateTime date)
|
||||||
{
|
{
|
||||||
var firstDay = date.GetFirstDayOfMonth();
|
var firstDay = date.GetFirstDayOfMonth();
|
||||||
@@ -210,66 +291,68 @@ public class CalendarView: TemplatedControl
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Click on Month Header button. Calendar switch from month mode to year mode.
|
/// Click on Month Header button. Calendar switch from month mode to year mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sender"></param>
|
/// <param name="sender"></param>
|
||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
private void OnHeaderMonthButtonClick(object sender, RoutedEventArgs e)
|
private void OnHeaderMonthButtonClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_headerButton?.SetValue(ContentControl.ContentProperty, ContextDate.Year);
|
_headerButton?.SetValue(ContentControl.ContentProperty, ContextDate.Year);
|
||||||
Mode = CalendarViewMode.Year;
|
SetCurrentValue(ModeProperty, CalendarViewMode.Year);
|
||||||
IsVisibleProperty.SetValue(true, _yearGrid);
|
|
||||||
IsVisibleProperty.SetValue(false, _monthGrid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Click on Year Header button. Calendar switch from month mode to decade mode.
|
/// Click on Year Header button. Calendar switch from month mode to decade mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sender"></param>
|
/// <param name="sender"></param>
|
||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
private void OnHeaderYearButtonClick(object sender, RoutedEventArgs e)
|
private void OnHeaderYearButtonClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (_yearGrid is null) return;
|
if (_yearGrid is null) return;
|
||||||
int? decadeStart = ContextDate.Year / 10 * 10;
|
var decadeStart = ContextDate.Year / 10 * 10;
|
||||||
_headerButton?.SetValue(ContentControl.ContentProperty,
|
_headerButton?.SetValue(ContentControl.ContentProperty, decadeStart + "-" + (decadeStart + 10));
|
||||||
decadeStart + "-" + (decadeStart + 10));
|
SetCurrentValue(ModeProperty, CalendarViewMode.Decade);
|
||||||
Mode = CalendarViewMode.Decade;
|
|
||||||
IsVisibleProperty.SetValue(true, _yearGrid);
|
|
||||||
IsVisibleProperty.SetValue(false, _monthGrid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Click on CalendarYearButton in YearView.
|
||||||
|
/// Mode switch rules are:
|
||||||
|
/// 1. Month -> Not supported, buttons are hidden.
|
||||||
|
/// 2. Year -> Month: Set the date to the selected year and switch to Month mode.
|
||||||
|
/// 3. Decade -> Year: Set the date to the selected year and switch to Year mode.
|
||||||
|
/// 4. Century -> Decade: Set the date to the selected year and switch to Decade mode.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender"></param>
|
||||||
|
/// <param name="e"></param>
|
||||||
private void OnYearItemSelected(object sender, CalendarYearButtonEventArgs e)
|
private void OnYearItemSelected(object sender, CalendarYearButtonEventArgs e)
|
||||||
{
|
{
|
||||||
if (_yearGrid is null) return;
|
if (_yearGrid is null) return;
|
||||||
var buttons = _yearGrid.Children.OfType<CalendarYearButton>().ToList();
|
var buttons = _yearGrid.Children.OfType<CalendarYearButton>().ToList();
|
||||||
if (e.Mode == CalendarViewMode.Year)
|
if (Mode == CalendarViewMode.Year)
|
||||||
{
|
{
|
||||||
|
Mode = CalendarViewMode.Month;
|
||||||
if (e.Month is null) return;
|
if (e.Month is null) return;
|
||||||
var day = MathHelpers.SafeClamp(e.Month.Value, 0,
|
var day = MathHelpers.SafeClamp(e.Month.Value, 0,
|
||||||
DateTime.DaysInMonth(ContextDate.Year!.Value, e.Month.Value + 1));
|
DateTime.DaysInMonth(ContextDate.Year!.Value, e.Month.Value + 1));
|
||||||
ContextDate = new DateContext { Year = ContextDate.Year, Month = e.Month + 1, Day = day };
|
ContextDate = new DateContext { Year = ContextDate.Year, Month = e.Month + 1, Day = day };
|
||||||
Mode = CalendarViewMode.Month;
|
|
||||||
}
|
}
|
||||||
else if (e.Mode == CalendarViewMode.Decade)
|
else if (Mode == CalendarViewMode.Decade)
|
||||||
{
|
{
|
||||||
// Set CalendarYearView to Month mode
|
Mode = CalendarViewMode.Year;
|
||||||
for (var i = 0; i < 12; i++)
|
for (var i = 0; i < 12; i++) buttons[i].SetValues(CalendarViewMode.Year, i);
|
||||||
{
|
ContextDate = new DateContext { Year = e.Year!.Value, Month = null, Day = null };
|
||||||
buttons[i].SetValues(CalendarViewMode.Month, month: i);
|
|
||||||
}
|
|
||||||
ContextDate = new DateContext() { Year = e.Year!.Value, Month = ContextDate.Month, Day = null };
|
|
||||||
Mode = CalendarViewMode.Month;
|
|
||||||
}
|
}
|
||||||
else if (e.Mode == CalendarViewMode.Century)
|
else if (Mode == CalendarViewMode.Century)
|
||||||
{
|
{
|
||||||
// Set CalendarYearView to Year mode
|
Mode = CalendarViewMode.Decade;
|
||||||
for (var i = 0; i < 12; i++)
|
for (var i = 0; i < 12; i++)
|
||||||
{
|
{
|
||||||
if (e.StartYear is null || e.EndYear is null) continue;
|
if (e.StartYear is null || e.EndYear is null) continue;
|
||||||
var year = e.StartYear.Value - 1 + i;
|
var year = e.StartYear.Value - 1 + i;
|
||||||
buttons[i].SetValues(CalendarViewMode.Year, year: year);
|
buttons[i].SetValues(CalendarViewMode.Decade, year: year);
|
||||||
}
|
}
|
||||||
Mode = CalendarViewMode.Year;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefreshYearButtons();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ using Irihi.Avalonia.Shared.Helpers;
|
|||||||
|
|
||||||
namespace Ursa.Controls;
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
|
/*
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Three modes:
|
/// Three modes:
|
||||||
/// 1. show 12 months in a year
|
/// 1. show 12 months in a year
|
||||||
@@ -117,3 +118,4 @@ public class CalendarYearView: TemplatedControl
|
|||||||
RefreshButtons();
|
RefreshButtons();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
Reference in New Issue
Block a user