Files
Wino-Mail/Wino.Mail.WinUI/Controls/Calendar/DayColumnControl.cs
T

151 lines
5.0 KiB
C#

using System;
using System.Collections.Specialized;
using System.Linq;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Wino.Core.Domain.Collections;
using Wino.Core.Domain.Models.Calendar;
namespace Wino.Calendar.Controls;
public partial class DayColumnControl : Control
{
private const string PART_HeaderDateDayText = nameof(PART_HeaderDateDayText);
private const string PART_IsTodayBorder = nameof(PART_IsTodayBorder);
private const string PART_ColumnHeaderText = nameof(PART_ColumnHeaderText);
private const string PART_AllDayItemsControl = nameof(PART_AllDayItemsControl);
private const string TodayState = nameof(TodayState);
private const string NotTodayState = nameof(NotTodayState);
private TextBlock? HeaderDateDayText;
private TextBlock? ColumnHeaderText;
private Border? IsTodayBorder;
private ItemsControl? AllDayItemsControl;
private CalendarEventCollection? _boundEventsCollection;
public CalendarDayModel DayModel
{
get { return (CalendarDayModel)GetValue(DayModelProperty); }
set { SetValue(DayModelProperty, value); }
}
public static readonly DependencyProperty DayModelProperty = DependencyProperty.Register(
nameof(DayModel),
typeof(CalendarDayModel),
typeof(DayColumnControl),
new PropertyMetadata(null, new PropertyChangedCallback(OnRenderingPropertiesChanged)));
public DayColumnControl()
{
DefaultStyleKey = typeof(DayColumnControl);
Unloaded += OnUnloaded;
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
HeaderDateDayText = GetTemplateChild(PART_HeaderDateDayText) as TextBlock;
ColumnHeaderText = GetTemplateChild(PART_ColumnHeaderText) as TextBlock;
IsTodayBorder = GetTemplateChild(PART_IsTodayBorder) as Border;
AllDayItemsControl = GetTemplateChild(PART_AllDayItemsControl) as ItemsControl;
RegisterEventsCollectionHandlers();
UpdateValues();
}
private static void OnRenderingPropertiesChanged(DependencyObject control, DependencyPropertyChangedEventArgs e)
{
if (control is DayColumnControl columnControl)
{
columnControl.RegisterEventsCollectionHandlers();
columnControl.UpdateValues();
}
}
private void OnUnloaded(object sender, RoutedEventArgs e)
{
DeregisterEventsCollectionHandlers();
}
private bool IsMonthlyTemplate() => ColumnHeaderText == null;
private void RegisterEventsCollectionHandlers()
{
var nextCollection = DayModel?.EventsCollection;
if (ReferenceEquals(_boundEventsCollection, nextCollection))
return;
DeregisterEventsCollectionHandlers();
_boundEventsCollection = nextCollection;
if (_boundEventsCollection == null)
return;
((INotifyCollectionChanged)_boundEventsCollection.AllDayEvents).CollectionChanged += EventsCollectionChanged;
((INotifyCollectionChanged)_boundEventsCollection.RegularEvents).CollectionChanged += EventsCollectionChanged;
}
private void DeregisterEventsCollectionHandlers()
{
if (_boundEventsCollection == null)
return;
((INotifyCollectionChanged)_boundEventsCollection.AllDayEvents).CollectionChanged -= EventsCollectionChanged;
((INotifyCollectionChanged)_boundEventsCollection.RegularEvents).CollectionChanged -= EventsCollectionChanged;
_boundEventsCollection = null;
}
private void EventsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
UpdateEventItemsSource();
}
private void UpdateEventItemsSource()
{
if (AllDayItemsControl == null || DayModel == null) return;
if (IsMonthlyTemplate())
{
// Month cells should show all events for the day, not only all-day/multi-day.
var monthlyItems = DayModel.EventsCollection.AllDayEvents
.Concat(DayModel.EventsCollection.RegularEvents)
.GroupBy(a => a.Id)
.Select(g => g.First())
.OrderBy(a => a.StartDate)
.ToList();
AllDayItemsControl.ItemsSource = monthlyItems;
return;
}
AllDayItemsControl.ItemsSource = DayModel.EventsCollection.AllDayEvents;
}
private void UpdateValues()
{
if (DayModel == null) return;
if (HeaderDateDayText != null)
{
HeaderDateDayText.Text = DayModel.RepresentingDate.Day.ToString();
}
// Monthly template does not use it.
if (ColumnHeaderText != null)
{
ColumnHeaderText.Text = DayModel.RepresentingDate.ToString("dddd", DayModel.CalendarRenderOptions.CalendarSettings.CultureInfo);
}
UpdateEventItemsSource();
if (IsTodayBorder == null) return;
bool isToday = DayModel.RepresentingDate.Date == DateTime.Now.Date;
VisualStateManager.GoToState(this, isToday ? TodayState : NotTodayState, false);
UpdateLayout();
}
}