feat: WIP retire MonthView and YearView.
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:CalendarDisplayControl/>
|
<u:CalendarView/>
|
||||||
</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:CalendarDisplayControl />
|
<u:CalendarView />
|
||||||
</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:CalendarDisplayControl}" TargetType="u:CalendarDisplayControl">
|
<ControlTheme x:Key="{x:Type u:CalendarView}" TargetType="u:CalendarView">
|
||||||
<Setter Property="MinHeight" Value="300" />
|
<Setter Property="MinHeight" Value="300" />
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<ControlTemplate TargetType="u:CalendarDisplayControl">
|
<ControlTemplate TargetType="u:CalendarView">
|
||||||
<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:CalendarDisplayControl.PART_PreviousYearButton}"
|
Name="{x:Static u:CalendarView.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:CalendarDisplayControl.PART_PreviousButton}"
|
Name="{x:Static u:CalendarView.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:CalendarDisplayControl.PART_YearButton}"
|
Name="{x:Static u:CalendarView.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:CalendarDisplayControl.PART_MonthButton}"
|
Name="{x:Static u:CalendarView.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:CalendarDisplayControl.PART_HeaderButton}"
|
Name="{x:Static u:CalendarView.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:CalendarDisplayControl.PART_NextButton}"
|
Name="{x:Static u:CalendarView.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:CalendarDisplayControl.PART_NextYearButton}"
|
Name="{x:Static u:CalendarView.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:CalendarDisplayControl.PART_MonthView}"
|
Name="{x:Static u:CalendarView.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:CalendarDisplayControl.PART_YearView}"
|
Name="{x:Static u:CalendarView.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,159 +0,0 @@
|
|||||||
using Avalonia;
|
|
||||||
using Avalonia.Collections;
|
|
||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Controls.Metadata;
|
|
||||||
using Avalonia.Controls.Primitives;
|
|
||||||
using Avalonia.Interactivity;
|
|
||||||
using Irihi.Avalonia.Shared.Helpers;
|
|
||||||
|
|
||||||
namespace Ursa.Controls;
|
|
||||||
|
|
||||||
[TemplatePart(PART_NextYearButton, typeof(Button))]
|
|
||||||
[TemplatePart(PART_PreviousYearButton, typeof(Button))]
|
|
||||||
[TemplatePart(PART_NextButton, typeof(Button))]
|
|
||||||
[TemplatePart(PART_PreviousButton, typeof(Button))]
|
|
||||||
[TemplatePart(PART_YearButton, typeof(Button))]
|
|
||||||
[TemplatePart(PART_MonthButton, typeof(Button))]
|
|
||||||
[TemplatePart(PART_HeaderButton, typeof(Button))]
|
|
||||||
[TemplatePart(PART_MonthView, typeof(CalendarMonthView))]
|
|
||||||
[TemplatePart(PART_YearView, typeof(CalendarYearView))]
|
|
||||||
public class CalendarDisplayControl: TemplatedControl
|
|
||||||
{
|
|
||||||
public const string PART_NextYearButton = "PART_NextYearButton";
|
|
||||||
public const string PART_PreviousYearButton = "PART_PreviousYearButton";
|
|
||||||
public const string PART_NextButton = "PART_NextButton";
|
|
||||||
public const string PART_PreviousButton = "PART_PreviousButton";
|
|
||||||
public const string PART_YearButton = "PART_YearButton";
|
|
||||||
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";
|
|
||||||
|
|
||||||
private CalendarMonthView? _monthView;
|
|
||||||
private CalendarYearView? _yearView;
|
|
||||||
// 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 event EventHandler<CalendarDayButtonEventArgs>? OnDateSelected;
|
|
||||||
public event EventHandler<CalendarDayButtonEventArgs>? OnDatePreviewed;
|
|
||||||
|
|
||||||
public static readonly StyledProperty<bool> IsTodayHighlightedProperty =
|
|
||||||
DatePickerBase.IsTodayHighlightedProperty.AddOwner<CalendarDisplayControl>();
|
|
||||||
public bool IsTodayHighlighted
|
|
||||||
{
|
|
||||||
get => GetValue(IsTodayHighlightedProperty);
|
|
||||||
set => SetValue(IsTodayHighlightedProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly StyledProperty<DayOfWeek> FirstDayOfWeekProperty =
|
|
||||||
DatePickerBase.FirstDayOfWeekProperty.AddOwner<CalendarDisplayControl>();
|
|
||||||
|
|
||||||
public DayOfWeek FirstDayOfWeek
|
|
||||||
{
|
|
||||||
get => GetValue(FirstDayOfWeekProperty);
|
|
||||||
set => SetValue(FirstDayOfWeekProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool _isMonthMode = true;
|
|
||||||
|
|
||||||
public static readonly DirectProperty<CalendarDisplayControl, bool> IsMonthModeProperty = AvaloniaProperty.RegisterDirect<CalendarDisplayControl, bool>(
|
|
||||||
nameof(IsMonthMode), o => o.IsMonthMode, (o, v) => o.IsMonthMode = v);
|
|
||||||
|
|
||||||
public bool IsMonthMode
|
|
||||||
{
|
|
||||||
get => _isMonthMode;
|
|
||||||
set => SetAndRaise(IsMonthModeProperty, ref _isMonthMode, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnApplyTemplate(e);
|
|
||||||
if (_monthView is not null)
|
|
||||||
{
|
|
||||||
_monthView.OnDateSelected -= OnMonthViewDateSelected;
|
|
||||||
_monthView.OnDatePreviewed -= OnMonthViewDatePreviewed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_yearView is not null)
|
|
||||||
{
|
|
||||||
_yearView.OnMonthSelected -= OnMonthSelected;
|
|
||||||
}
|
|
||||||
Button.ClickEvent.RemoveHandler(OnYearButtonClick, _yearButton);
|
|
||||||
Button.ClickEvent.RemoveHandler(OnMonthButtonClick, _monthButton);
|
|
||||||
Button.ClickEvent.RemoveHandler(OnHeaderButtonClick, _headerButton);
|
|
||||||
_monthView = e.NameScope.Find<CalendarMonthView>(PART_MonthView);
|
|
||||||
_yearView = e.NameScope.Find<CalendarYearView>(PART_YearView);
|
|
||||||
_yearButton = e.NameScope.Find<Button>(PART_YearButton);
|
|
||||||
_monthButton = e.NameScope.Find<Button>(PART_MonthButton);
|
|
||||||
_headerButton = e.NameScope.Find<Button>(PART_HeaderButton);
|
|
||||||
if(_monthView is not null)
|
|
||||||
{
|
|
||||||
_monthView.OnDateSelected += OnMonthViewDateSelected;
|
|
||||||
_monthView.OnDatePreviewed += OnMonthViewDatePreviewed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_yearView is not null)
|
|
||||||
{
|
|
||||||
_yearView.OnMonthSelected += OnMonthSelected;
|
|
||||||
}
|
|
||||||
Button.ClickEvent.AddHandler(OnYearButtonClick, _yearButton);
|
|
||||||
Button.ClickEvent.AddHandler(OnMonthButtonClick, _monthButton);
|
|
||||||
Button.ClickEvent.AddHandler(OnHeaderButtonClick, _headerButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Rule:
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender"></param>
|
|
||||||
/// <param name="e"></param>
|
|
||||||
private void OnHeaderButtonClick(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (_yearView?.Mode == CalendarYearViewMode.Month)
|
|
||||||
{
|
|
||||||
_headerButton?.SetValue(ContentControl.ContentProperty, _yearView.ContextDate.Year);
|
|
||||||
_yearView?.UpdateMode(CalendarYearViewMode.Year);
|
|
||||||
}
|
|
||||||
else if (_yearView?.Mode == CalendarYearViewMode.Year)
|
|
||||||
{
|
|
||||||
_headerButton?.SetCurrentValue(ContentControl.ContentProperty,
|
|
||||||
_yearView.ContextDate.Year + "-" + (_yearView.ContextDate.Year + 100));
|
|
||||||
_yearView?.UpdateMode(CalendarYearViewMode.YearRange);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnMonthSelected(object sender, CalendarYearButtonEventArgs e)
|
|
||||||
{
|
|
||||||
SetCurrentValue(IsMonthModeProperty, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnMonthButtonClick(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
SetCurrentValue(IsMonthModeProperty, false);
|
|
||||||
if (_yearView is null) return;
|
|
||||||
_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(ContentControl.ContentProperty,
|
|
||||||
_yearView?.ContextDate.Year + "-" + (_yearView?.ContextDate.Year + 10));
|
|
||||||
_yearView?.UpdateMode(CalendarYearViewMode.Year);
|
|
||||||
SetCurrentValue(IsMonthModeProperty, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnMonthViewDatePreviewed(object sender, CalendarDayButtonEventArgs e)
|
|
||||||
{
|
|
||||||
OnDatePreviewed?.Invoke(sender, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnMonthViewDateSelected(object sender, CalendarDayButtonEventArgs e)
|
|
||||||
{
|
|
||||||
OnDateSelected?.Invoke(sender, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -33,7 +33,7 @@ public class CalendarMonthView : TemplatedControl
|
|||||||
view.OnDayOfWeekChanged(args));
|
view.OnDayOfWeekChanged(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal CalendarDisplayControl? Owner { get; set; }
|
internal CalendarView? 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.
|
||||||
|
|||||||
275
src/Ursa/Controls/DateTimePicker/CalendarView.cs
Normal file
275
src/Ursa/Controls/DateTimePicker/CalendarView.cs
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
using System.Reflection;
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Collections;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Metadata;
|
||||||
|
using Avalonia.Controls.Primitives;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.Layout;
|
||||||
|
using Avalonia.Media.TextFormatting;
|
||||||
|
using Irihi.Avalonia.Shared.Helpers;
|
||||||
|
|
||||||
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
|
[TemplatePart(PART_NextYearButton, typeof(Button))]
|
||||||
|
[TemplatePart(PART_PreviousYearButton, typeof(Button))]
|
||||||
|
[TemplatePart(PART_NextButton, typeof(Button))]
|
||||||
|
[TemplatePart(PART_PreviousButton, typeof(Button))]
|
||||||
|
[TemplatePart(PART_YearButton, typeof(Button))]
|
||||||
|
[TemplatePart(PART_MonthButton, typeof(Button))]
|
||||||
|
[TemplatePart(PART_HeaderButton, typeof(Button))]
|
||||||
|
[TemplatePart(PART_MonthView, typeof(CalendarMonthView))]
|
||||||
|
[TemplatePart(PART_YearView, typeof(CalendarYearView))]
|
||||||
|
[TemplatePart(PART_MonthGrid, typeof(Grid))]
|
||||||
|
[TemplatePart(PART_YearGrid, typeof(Grid))]
|
||||||
|
public class CalendarView: TemplatedControl
|
||||||
|
{
|
||||||
|
public const string PART_NextYearButton = "PART_NextYearButton";
|
||||||
|
public const string PART_PreviousYearButton = "PART_PreviousYearButton";
|
||||||
|
public const string PART_NextButton = "PART_NextButton";
|
||||||
|
public const string PART_PreviousButton = "PART_PreviousButton";
|
||||||
|
public const string PART_YearButton = "PART_YearButton";
|
||||||
|
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_MonthGrid = "PART_MonthGrid";
|
||||||
|
public const string PART_YearGrid = "PART_YearGried";
|
||||||
|
|
||||||
|
private const string ShortestDayName = "ShortestDayName";
|
||||||
|
|
||||||
|
private readonly System.Globalization.Calendar _calendar = new GregorianCalendar();
|
||||||
|
|
||||||
|
internal CalendarViewMode Mode;
|
||||||
|
|
||||||
|
//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 =
|
||||||
|
DatePickerBase.IsTodayHighlightedProperty.AddOwner<CalendarView>();
|
||||||
|
public bool IsTodayHighlighted
|
||||||
|
{
|
||||||
|
get => GetValue(IsTodayHighlightedProperty);
|
||||||
|
set => SetValue(IsTodayHighlightedProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<DayOfWeek> FirstDayOfWeekProperty =
|
||||||
|
DatePickerBase.FirstDayOfWeekProperty.AddOwner<CalendarView>();
|
||||||
|
|
||||||
|
public DayOfWeek FirstDayOfWeek
|
||||||
|
{
|
||||||
|
get => GetValue(FirstDayOfWeekProperty);
|
||||||
|
set => SetValue(FirstDayOfWeekProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnApplyTemplate(e);
|
||||||
|
|
||||||
|
Button.ClickEvent.RemoveHandler(OnHeaderYearButtonClick, _yearButton);
|
||||||
|
Button.ClickEvent.RemoveHandler(OnHeaderMonthButtonClick, _monthButton);
|
||||||
|
Button.ClickEvent.RemoveHandler(OnHeaderButtonClick, _headerButton);
|
||||||
|
|
||||||
|
_monthGrid = e.NameScope.Find<Grid>(PART_MonthGrid);
|
||||||
|
_yearGrid = e.NameScope.Find<Grid>(PART_YearGrid);
|
||||||
|
_yearButton = e.NameScope.Find<Button>(PART_YearButton);
|
||||||
|
_monthButton = e.NameScope.Find<Button>(PART_MonthButton);
|
||||||
|
_headerButton = e.NameScope.Find<Button>(PART_HeaderButton);
|
||||||
|
|
||||||
|
Button.ClickEvent.AddHandler(OnHeaderYearButtonClick, _yearButton);
|
||||||
|
Button.ClickEvent.AddHandler(OnHeaderMonthButtonClick, _monthButton);
|
||||||
|
Button.ClickEvent.AddHandler(OnHeaderButtonClick, _headerButton);
|
||||||
|
|
||||||
|
GenerateGridElements();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rule:
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender"></param>
|
||||||
|
/// <param name="e"></param>
|
||||||
|
private void OnHeaderButtonClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (Mode == CalendarViewMode.Month)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Mode == CalendarViewMode.Year)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generate Buttons and labels for MonthView.
|
||||||
|
/// Generate Buttons for YearView.
|
||||||
|
/// </summary>
|
||||||
|
private void GenerateGridElements()
|
||||||
|
{
|
||||||
|
// Generate Day titles (Sun, Mon, Tue, Wed, Thu, Fri, Sat) based on FirstDayOfWeek and culture.
|
||||||
|
var count = 7 + 7 * 7;
|
||||||
|
var children = new List<Control>(count);
|
||||||
|
var dayOfWeek = (int)FirstDayOfWeek;
|
||||||
|
var info = DateTimeHelper.GetCurrentDateTimeFormatInfo();
|
||||||
|
for (var i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
var d = (dayOfWeek + i) % DateTimeHelper.NumberOfDaysPerWeek;
|
||||||
|
var cell = new TextBlock { Text = info.ShortestDayNames[d], Tag = ShortestDayName };
|
||||||
|
cell.SetValue(HorizontalAlignmentProperty, HorizontalAlignment.Center);
|
||||||
|
cell.SetValue(Grid.RowProperty, 0);
|
||||||
|
cell.SetValue(Grid.ColumnProperty, i);
|
||||||
|
children.Add(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate day buttons.
|
||||||
|
for (var i = 2; i < DateTimeHelper.NumberOfWeeksPerMonth + 2; i++)
|
||||||
|
for (var j = 0; j < DateTimeHelper.NumberOfDaysPerWeek; j++)
|
||||||
|
{
|
||||||
|
var cell = new CalendarDayButton();
|
||||||
|
cell.SetValue(Grid.RowProperty, i);
|
||||||
|
cell.SetValue(Grid.ColumnProperty, j);
|
||||||
|
cell.AddHandler(CalendarDayButton.DateSelectedEvent, OnCellDateSelected);
|
||||||
|
cell.AddHandler(CalendarDayButton.DatePreviewedEvent, OnCellDatePreviewed);
|
||||||
|
children.Add(cell);
|
||||||
|
}
|
||||||
|
_monthGrid?.Children.AddRange(children);
|
||||||
|
|
||||||
|
// Generate month/year buttons.
|
||||||
|
for (var i = 0; i < 12; i++)
|
||||||
|
{
|
||||||
|
var button = new CalendarYearButton();
|
||||||
|
Grid.SetRow(button, i / 3);
|
||||||
|
Grid.SetColumn(button, i % 3);
|
||||||
|
button.AddHandler(CalendarYearButton.ItemSelectedEvent, OnYearItemSelected);
|
||||||
|
_yearGrid?.Children.Add(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshButtons(DateTime date)
|
||||||
|
{
|
||||||
|
if (_monthGrid is null) return;
|
||||||
|
var children = _monthGrid.Children;
|
||||||
|
var info = DateTimeHelper.GetCurrentDateTimeFormatInfo();
|
||||||
|
var dayBefore = PreviousMonthDays(date);
|
||||||
|
var dateToSet = date.GetFirstDayOfMonth().AddDays(-dayBefore);
|
||||||
|
for (var i = 8; i < children.Count; i++)
|
||||||
|
{
|
||||||
|
var day = dateToSet;
|
||||||
|
var cell = children[i] as CalendarDayButton;
|
||||||
|
if (cell is null) continue;
|
||||||
|
cell.DataContext = day;
|
||||||
|
cell.IsToday = day == DateTime.Today;
|
||||||
|
cell.Content = day.Day.ToString(info);
|
||||||
|
dateToSet = dateToSet.AddDays(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
FadeOutDayButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FadeOutDayButtons()
|
||||||
|
{
|
||||||
|
if (_monthGrid is null) return;
|
||||||
|
var children = _monthGrid.Children;
|
||||||
|
for (var i = 8; i < children.Count; i++)
|
||||||
|
if (children[i] is CalendarDayButton { DataContext: DateTime d } button && d.Month != ContextDate.Month)
|
||||||
|
button.IsNotCurrentMonth = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int PreviousMonthDays(DateTime date)
|
||||||
|
{
|
||||||
|
var firstDay = date.GetFirstDayOfMonth();
|
||||||
|
var dayOfWeek = _calendar.GetDayOfWeek(firstDay);
|
||||||
|
var firstDayOfWeek = FirstDayOfWeek;
|
||||||
|
var i = (dayOfWeek - firstDayOfWeek + DateTimeHelper.NumberOfDaysPerWeek) % DateTimeHelper.NumberOfDaysPerWeek;
|
||||||
|
return i == 0 ? DateTimeHelper.NumberOfDaysPerWeek : i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCellDatePreviewed(object sender, CalendarDayButtonEventArgs e)
|
||||||
|
{
|
||||||
|
OnDatePreviewed?.Invoke(sender, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCellDateSelected(object sender, CalendarDayButtonEventArgs e)
|
||||||
|
{
|
||||||
|
OnDateSelected?.Invoke(sender, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Click on Month Header button. Calendar switch from month mode to year mode.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender"></param>
|
||||||
|
/// <param name="e"></param>
|
||||||
|
private void OnHeaderMonthButtonClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
_headerButton?.SetValue(ContentControl.ContentProperty, ContextDate.Year);
|
||||||
|
Mode = CalendarViewMode.Year;
|
||||||
|
IsVisibleProperty.SetValue(true, _yearGrid);
|
||||||
|
IsVisibleProperty.SetValue(false, _monthGrid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Click on Year Header button. Calendar switch from month mode to decade mode.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender"></param>
|
||||||
|
/// <param name="e"></param>
|
||||||
|
private void OnHeaderYearButtonClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (_yearGrid is null) return;
|
||||||
|
int? decadeStart = ContextDate.Year / 10 * 10;
|
||||||
|
_headerButton?.SetValue(ContentControl.ContentProperty,
|
||||||
|
decadeStart + "-" + (decadeStart + 10));
|
||||||
|
Mode = CalendarViewMode.Decade;
|
||||||
|
IsVisibleProperty.SetValue(true, _yearGrid);
|
||||||
|
IsVisibleProperty.SetValue(false, _monthGrid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnYearItemSelected(object sender, CalendarYearButtonEventArgs e)
|
||||||
|
{
|
||||||
|
if (_yearGrid is null) return;
|
||||||
|
var buttons = _yearGrid.Children.OfType<CalendarYearButton>().ToList();
|
||||||
|
if (e.Mode == CalendarViewMode.Year)
|
||||||
|
{
|
||||||
|
if (e.Month is null) return;
|
||||||
|
var day = MathHelpers.SafeClamp(e.Month.Value, 0,
|
||||||
|
DateTime.DaysInMonth(ContextDate.Year!.Value, e.Month.Value + 1));
|
||||||
|
ContextDate = new DateContext { Year = ContextDate.Year, Month = e.Month + 1, Day = day };
|
||||||
|
Mode = CalendarViewMode.Month;
|
||||||
|
}
|
||||||
|
else if (e.Mode == CalendarViewMode.Decade)
|
||||||
|
{
|
||||||
|
// Set CalendarYearView to Month mode
|
||||||
|
for (var i = 0; i < 12; i++)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
// Set CalendarYearView to Year mode
|
||||||
|
for (var i = 0; i < 12; i++)
|
||||||
|
{
|
||||||
|
if (e.StartYear is null || e.EndYear is null) continue;
|
||||||
|
var year = e.StartYear.Value - 1 + i;
|
||||||
|
buttons[i].SetValues(CalendarViewMode.Year, year: year);
|
||||||
|
}
|
||||||
|
Mode = CalendarViewMode.Year;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/Ursa/Controls/DateTimePicker/CalendarViewMode.cs
Normal file
13
src/Ursa/Controls/DateTimePicker/CalendarViewMode.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
|
internal enum CalendarViewMode
|
||||||
|
{
|
||||||
|
// Show days in current month.
|
||||||
|
Month,
|
||||||
|
// Show Months in current year.
|
||||||
|
Year,
|
||||||
|
// The button represents 10(12) years.
|
||||||
|
Decade,
|
||||||
|
// The button represents 100(120) years.
|
||||||
|
Century,
|
||||||
|
}
|
||||||
@@ -8,15 +8,6 @@ using Irihi.Avalonia.Shared.Common;
|
|||||||
|
|
||||||
namespace Ursa.Controls;
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
internal enum CalendarYearViewMode
|
|
||||||
{
|
|
||||||
Month,
|
|
||||||
Year,
|
|
||||||
|
|
||||||
// The button represents 10 years.
|
|
||||||
YearRange
|
|
||||||
}
|
|
||||||
|
|
||||||
[PseudoClasses(PC_Range, PseudoClassName.PC_Selected)]
|
[PseudoClasses(PC_Range, PseudoClassName.PC_Selected)]
|
||||||
public class CalendarYearButton : ContentControl
|
public class CalendarYearButton : ContentControl
|
||||||
{
|
{
|
||||||
@@ -31,15 +22,15 @@ public class CalendarYearButton : ContentControl
|
|||||||
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 CalendarViewMode Mode { get; private set; }
|
||||||
|
|
||||||
public event EventHandler<CalendarDayButtonEventArgs> ItemSelected
|
public event EventHandler<CalendarDayButtonEventArgs> ItemSelected
|
||||||
{
|
{
|
||||||
@@ -47,7 +38,7 @@ public class CalendarYearButton : ContentControl
|
|||||||
remove => RemoveHandler(ItemSelectedEvent, value);
|
remove => RemoveHandler(ItemSelectedEvent, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void SetValues(CalendarYearViewMode mode, DateTime contextDate, int? month = null, int? year = null,
|
internal void SetValues(CalendarViewMode mode, int? month = null, int? year = null,
|
||||||
int? startYear = null, int? endYear = 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));
|
||||||
@@ -58,9 +49,10 @@ public class CalendarYearButton : ContentControl
|
|||||||
EndYear = endYear ?? 0;
|
EndYear = endYear ?? 0;
|
||||||
Content = Mode switch
|
Content = Mode switch
|
||||||
{
|
{
|
||||||
CalendarYearViewMode.Month => DateTimeHelper.GetCurrentDateTimeFormatInfo().AbbreviatedMonthNames[Month],
|
CalendarViewMode.Month => DateTimeHelper.GetCurrentDateTimeFormatInfo().AbbreviatedMonthNames[Month.Value],
|
||||||
CalendarYearViewMode.Year => Year.ToString(),
|
CalendarViewMode.Year => Year.ToString(),
|
||||||
CalendarYearViewMode.YearRange => StartYear + "-" + EndYear,
|
CalendarViewMode.Decade => StartYear + "-" + EndYear,
|
||||||
|
CalendarViewMode.Century => StartYear + "-" + EndYear,
|
||||||
_ => Content
|
_ => Content
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ public class CalendarYearButtonEventArgs: RoutedEventArgs
|
|||||||
public int? Month { get; }
|
public int? Month { get; }
|
||||||
public int? StartYear { get; }
|
public int? StartYear { get; }
|
||||||
public int? EndYear { get; }
|
public int? EndYear { get; }
|
||||||
internal CalendarYearViewMode Mode { get; }
|
internal CalendarViewMode Mode { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
internal CalendarYearButtonEventArgs(CalendarYearViewMode mode, int? year, int? month, int? startYear, int? endYear )
|
internal CalendarYearButtonEventArgs(CalendarViewMode mode, int? year, int? month, int? startYear, int? endYear )
|
||||||
{
|
{
|
||||||
Year = year;
|
Year = year;
|
||||||
Month = month;
|
Month = month;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public class CalendarYearView: TemplatedControl
|
|||||||
|
|
||||||
public event EventHandler<CalendarYearButtonEventArgs>? OnMonthSelected;
|
public event EventHandler<CalendarYearButtonEventArgs>? OnMonthSelected;
|
||||||
|
|
||||||
internal CalendarYearViewMode Mode { get; set; } = CalendarYearViewMode.Month;
|
internal CalendarViewMode Mode { get; set; } = CalendarViewMode.Month;
|
||||||
internal DateTime ContextDate { get; set; } = DateTime.Today;
|
internal DateTime ContextDate { get; set; } = DateTime.Today;
|
||||||
|
|
||||||
private Grid? _grid;
|
private Grid? _grid;
|
||||||
@@ -55,33 +55,33 @@ public class CalendarYearView: TemplatedControl
|
|||||||
{
|
{
|
||||||
if (_grid is null) return;
|
if (_grid is null) return;
|
||||||
var buttons = _grid.Children.OfType<CalendarYearButton>().ToList();
|
var buttons = _grid.Children.OfType<CalendarYearButton>().ToList();
|
||||||
if (e.Mode == CalendarYearViewMode.Month)
|
if (e.Mode == CalendarViewMode.Month)
|
||||||
{
|
{
|
||||||
if (e.Month is null) return;
|
if (e.Month is null) return;
|
||||||
var day = MathHelpers.SafeClamp(e.Month.Value, 0, DateTime.DaysInMonth(ContextDate.Year, e.Month.Value+1));
|
var day = MathHelpers.SafeClamp(e.Month.Value, 0, DateTime.DaysInMonth(ContextDate.Year, e.Month.Value+1));
|
||||||
ContextDate = new DateTime(ContextDate.Year, e.Month.Value+1, day+1);
|
ContextDate = new DateTime(ContextDate.Year, e.Month.Value+1, day+1);
|
||||||
OnMonthSelected?.Invoke(this, e);
|
OnMonthSelected?.Invoke(this, e);
|
||||||
}
|
}
|
||||||
else if (e.Mode == CalendarYearViewMode.Year)
|
else if (e.Mode == CalendarViewMode.Year)
|
||||||
{
|
{
|
||||||
// Set CalendarYearView to Month mode
|
// Set CalendarYearView to Month mode
|
||||||
for (var i = 0; i < 12; i++)
|
for (var i = 0; i < 12; i++)
|
||||||
{
|
{
|
||||||
buttons[i].SetValues(CalendarYearViewMode.Month, ContextDate, month: i);
|
buttons[i].SetValues(CalendarViewMode.Month, month: i);
|
||||||
}
|
}
|
||||||
ContextDate = new DateTime(e.Year!.Value, ContextDate.Month, 1);
|
ContextDate = new DateTime(e.Year!.Value, ContextDate.Month, 1);
|
||||||
Mode = CalendarYearViewMode.Month;
|
Mode = CalendarViewMode.Month;
|
||||||
}
|
}
|
||||||
else if (e.Mode == CalendarYearViewMode.YearRange)
|
else if (e.Mode == CalendarViewMode.Decade)
|
||||||
{
|
{
|
||||||
// Set CalendarYearView to Year mode
|
// Set CalendarYearView to Year mode
|
||||||
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(CalendarYearViewMode.Year, ContextDate, year: year);
|
buttons[i].SetValues(CalendarViewMode.Year, year: year);
|
||||||
}
|
}
|
||||||
Mode = CalendarYearViewMode.Year;
|
Mode = CalendarViewMode.Year;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,22 +96,22 @@ public class CalendarYearView: TemplatedControl
|
|||||||
if (child is null) continue;
|
if (child is null) continue;
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case CalendarYearViewMode.Month:
|
case CalendarViewMode.Month:
|
||||||
child.SetValues(CalendarYearViewMode.Month, contextDate, month: i);
|
child.SetValues(CalendarViewMode.Month, month: i);
|
||||||
break;
|
break;
|
||||||
case CalendarYearViewMode.Year:
|
case CalendarViewMode.Year:
|
||||||
child.SetValues(CalendarYearViewMode.Year, contextDate, year: ContextDate.Year / 10 * 10 + i - 1);
|
child.SetValues(CalendarViewMode.Year, year: ContextDate.Year / 10 * 10 + i - 1);
|
||||||
break;
|
break;
|
||||||
case CalendarYearViewMode.YearRange:
|
case CalendarViewMode.Decade:
|
||||||
var startYear = (ContextDate.Year / 10 + i - 1) * 10;
|
var startYear = (ContextDate.Year / 10 + i - 1) * 10;
|
||||||
var endYear = (ContextDate.Year / 10 + i - 1) * 10 + 10;
|
var endYear = (ContextDate.Year / 10 + i - 1) * 10 + 10;
|
||||||
child.SetValues(CalendarYearViewMode.YearRange, contextDate, startYear: startYear, endYear: endYear);
|
child.SetValues(CalendarViewMode.Decade, startYear: startYear, endYear: endYear);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void UpdateMode(CalendarYearViewMode mode)
|
internal void UpdateMode(CalendarViewMode mode)
|
||||||
{
|
{
|
||||||
Mode = mode;
|
Mode = mode;
|
||||||
RefreshButtons();
|
RefreshButtons();
|
||||||
|
|||||||
8
src/Ursa/Controls/DateTimePicker/DateContext.cs
Normal file
8
src/Ursa/Controls/DateTimePicker/DateContext.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
|
public class DateContext(int? year = null, int? month = null, int? day = null)
|
||||||
|
{
|
||||||
|
public int? Year = year;
|
||||||
|
public int? Month = month;
|
||||||
|
public int? Day = day;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user