Browse Source

wpf: Added regions to Calendar Control

Kenric Nugteren 1 month ago
parent
commit
986c667acf
1 changed files with 151 additions and 1 deletions
  1. 151 1
      inabox.wpf/Forms/CalendarControl/CalendarControl.cs

+ 151 - 1
inabox.wpf/Forms/CalendarControl/CalendarControl.cs

@@ -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) =>
                     {