|
|
@@ -11,6 +11,7 @@ using System.ComponentModel;
|
|
|
using System.Diagnostics.CodeAnalysis;
|
|
|
using System.Linq;
|
|
|
using System.Reactive.Linq;
|
|
|
+using System.Runtime.CompilerServices;
|
|
|
using System.Text;
|
|
|
using System.Threading;
|
|
|
using System.Threading.Tasks;
|
|
|
@@ -34,6 +35,70 @@ public class CalendarBlockEventArgs(object? value, object column, DateTime date,
|
|
|
public TimeSpan End { get; set; } = end;
|
|
|
}
|
|
|
|
|
|
+public class CalendarRegion : INotifyPropertyChanged
|
|
|
+{
|
|
|
+ private DateTime _date;
|
|
|
+ public DateTime Date
|
|
|
+ {
|
|
|
+ get => _date;
|
|
|
+ set
|
|
|
+ {
|
|
|
+ _date = value;
|
|
|
+ OnPropertyChanged();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private object? _column;
|
|
|
+ public object? Column
|
|
|
+ {
|
|
|
+ get => _column;
|
|
|
+ set
|
|
|
+ {
|
|
|
+ _column = value;
|
|
|
+ OnPropertyChanged();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private TimeSpan _start;
|
|
|
+ public TimeSpan Start
|
|
|
+ {
|
|
|
+ get => _start;
|
|
|
+ set
|
|
|
+ {
|
|
|
+ _start = value;
|
|
|
+ OnPropertyChanged();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private TimeSpan _end;
|
|
|
+ public TimeSpan End
|
|
|
+ {
|
|
|
+ get => _end;
|
|
|
+ set
|
|
|
+ {
|
|
|
+ _end = value;
|
|
|
+ OnPropertyChanged();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private Brush? _background;
|
|
|
+ public Brush? Background
|
|
|
+ {
|
|
|
+ get => _background;
|
|
|
+ set
|
|
|
+ {
|
|
|
+ _background = value;
|
|
|
+ OnPropertyChanged();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public event PropertyChangedEventHandler? PropertyChanged;
|
|
|
+ private void OnPropertyChanged([CallerMemberName] string? name = null)
|
|
|
+ {
|
|
|
+ PropertyChanged?.Invoke(this, new(name));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
public class CalendarControl : ContentControl
|
|
|
{
|
|
|
public static readonly DependencyProperty RowHeightProperty =
|
|
|
@@ -60,6 +125,10 @@ public class CalendarControl : ContentControl
|
|
|
public static readonly DependencyProperty ColumnsProperty =
|
|
|
DependencyProperty.Register(nameof(Columns), typeof(IEnumerable), typeof(CalendarControl), new(Columns_Changed));
|
|
|
|
|
|
+ public static readonly DependencyProperty RegionsProperty =
|
|
|
+ DependencyProperty.Register(nameof(Regions), typeof(IEnumerable<CalendarRegion>), typeof(CalendarControl), new(Regions_Changed));
|
|
|
+
|
|
|
+
|
|
|
public double MinimumColumnWidth
|
|
|
{
|
|
|
get => (double)GetValue(MinimumColumnWidthProperty);
|
|
|
@@ -116,6 +185,12 @@ public class CalendarControl : ContentControl
|
|
|
set => SetValue(ColumnsProperty, value);
|
|
|
}
|
|
|
|
|
|
+ public IEnumerable<CalendarRegion>? Regions
|
|
|
+ {
|
|
|
+ get => GetValue(RegionsProperty) as IEnumerable<CalendarRegion>;
|
|
|
+ set => SetValue(RegionsProperty, value);
|
|
|
+ }
|
|
|
+
|
|
|
public event EventHandler<CalendarBlockEventArgs>? BlockClicked;
|
|
|
public event EventHandler<CalendarBlockEventArgs>? BlockHeld;
|
|
|
|
|
|
@@ -134,6 +209,59 @@ public class CalendarControl : ContentControl
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private static void Regions_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
|
+ {
|
|
|
+ if (d is not CalendarControl calendar) return;
|
|
|
+
|
|
|
+ if(e.OldValue is IEnumerable<CalendarRegion> regions)
|
|
|
+ {
|
|
|
+ foreach(var item in regions)
|
|
|
+ {
|
|
|
+ item.PropertyChanged -= calendar.Region_PropertyChanged;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(e.OldValue is INotifyCollectionChanged oldNotify)
|
|
|
+ {
|
|
|
+ oldNotify.CollectionChanged -= calendar.RegionsCollection_Changed;
|
|
|
+ }
|
|
|
+ calendar.UpdateRegionBinding();
|
|
|
+ calendar.Render();
|
|
|
+ if(e.NewValue is INotifyCollectionChanged notify)
|
|
|
+ {
|
|
|
+ notify.CollectionChanged += calendar.RegionsCollection_Changed;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void UpdateRegionBinding()
|
|
|
+ {
|
|
|
+ if(Regions is null)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ foreach(var region in Regions)
|
|
|
+ {
|
|
|
+ region.PropertyChanged -= Region_PropertyChanged;
|
|
|
+ region.PropertyChanged += Region_PropertyChanged;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void Region_PropertyChanged(object? sender, PropertyChangedEventArgs e)
|
|
|
+ {
|
|
|
+ if(e.PropertyName == nameof(CalendarRegion.Start)
|
|
|
+ || e.PropertyName == nameof(CalendarRegion.End)
|
|
|
+ || e.PropertyName == nameof(CalendarRegion.Date)
|
|
|
+ || e.PropertyName == nameof(CalendarRegion.Column))
|
|
|
+ {
|
|
|
+ Render();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void RegionsCollection_Changed(object? sender, NotifyCollectionChangedEventArgs e)
|
|
|
+ {
|
|
|
+ UpdateRegionBinding();
|
|
|
+ Render();
|
|
|
+ }
|
|
|
+
|
|
|
private void ColumnsCollection_Changed(object? sender, NotifyCollectionChangedEventArgs e)
|
|
|
{
|
|
|
Render(columnsChanged: true);
|
|
|
@@ -660,6 +788,9 @@ public class CalendarControl : ContentControl
|
|
|
var dates = _blocks.Keys.ToArray();
|
|
|
Array.Sort(dates);
|
|
|
|
|
|
+ var regions = (Regions ?? Enumerable.Empty<CalendarRegion>())
|
|
|
+ .GroupByDictionary(x => (x.Date, x.Column));
|
|
|
+
|
|
|
_columnList.Clear();
|
|
|
var columnIdx = 0;
|
|
|
foreach(var date in dates)
|
|
|
@@ -702,6 +833,25 @@ public class CalendarControl : ContentControl
|
|
|
columnHeader.SizeChanged += ColumnHeader_SizeChanged;
|
|
|
}
|
|
|
|
|
|
+ // Add regions
|
|
|
+ if(regions.TryGetValue((date, columnKey), out var columnRegions))
|
|
|
+ {
|
|
|
+ foreach(var region in columnRegions)
|
|
|
+ {
|
|
|
+ var rectangle = new Rectangle
|
|
|
+ {
|
|
|
+ Width = colWidth * columnBlocks.Columns!.Count,
|
|
|
+ Height = ((region.End - region.Start).TotalHours / RowInterval.TotalHours) * RowHeight,
|
|
|
+ };
|
|
|
+
|
|
|
+ rectangle.Bind(Rectangle.FillProperty, region, x => x.Background);
|
|
|
+
|
|
|
+ Canvas.SetLeft(rectangle, colX);
|
|
|
+ Canvas.SetTop(rectangle, ((region.End - region.Start).TotalHours / RowInterval.TotalHours) * RowHeight);
|
|
|
+ MainCanvas.Children.Add(rectangle);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// Add cell placeholders
|
|
|
var rowIdx = 0;
|
|
|
for(var time = TimeSpan.Zero; time < TimeSpan.FromHours(24); time += RowInterval)
|
|
|
@@ -714,7 +864,7 @@ public class CalendarControl : ContentControl
|
|
|
};
|
|
|
rectangle.MouseEnter += (o, e) =>
|
|
|
{
|
|
|
- rectangle.Fill = Colors.LightBlue.ToBrush();
|
|
|
+ rectangle.Fill = Colors.LightBlue.ToBrush(0.5);
|
|
|
};
|
|
|
rectangle.MouseLeave += (o, e) =>
|
|
|
{
|