/// <summary>
        /// Returns how many days into an event the specified label starts
        /// (if it's not the first label of the event).
        /// </summary>
        private int GetLabelDayOffset(DraggableView label)
        {
            if (label == null)
            {
                return 0;
            }

            var ev = label.BindingContext as Event;

            if (ev == null)
            {
                return 0;
            }

            var labelDate = GetLabelStartDate(label);

            if (!labelDate.HasValue)
            {
                return 0;
            }

            return (labelDate.Value - ev.Start.Date).Days;
        }
        /// <summary>
        /// Get the start date for a specified label (may be later than the start date of the event)
        /// </summary>
        /// <param name="label">Label to get start date for</param>
        /// <returns>Start date, or null if not found</returns>
        private DateTime? GetLabelStartDate(DraggableView label)
        {
            if (label == null)
            {
                return null;
            }

            var column = AutoStackGrid.GetColumn(label);
            var row = Grid.GetRow(label.ParentView);

            var calendarCell = _grid.Children.OfType<CalendarCellView>()
                .FirstOrDefault(cell => Grid.GetRow(cell) == row && Grid.GetColumn(cell) == column);

            return calendarCell?.BindingContext as DateTime?;
        }
        /// <summary>
        /// Takes the center point from a drag event and calculates the point to use
        /// for hit testing (e.g., we want to use the center of the first day of the
        /// label, not the center of the whole label) relative to the calendar grid.
        /// </summary>
        /// <param name="center">Center point of the dragged label, relative to its immediate parent</param>
        /// <param name="label">Label being dragged</param>
        /// <returns>Calculated destination point</returns>
        private Point GetDragDestinationPoint(Point center, DraggableView label)
        {
            var newCenterPoint = center;
            var colSpan = AutoStackGrid.GetColumnSpan(label);

            newCenterPoint = label.ParentView.TranslatePointToAncestor(newCenterPoint, _grid);

            // Adjust point for ColumnSpan (i.e., it's the starting day we care about)
            //
            if (colSpan > 1)
            {
                var labelWidth = label.Bounds.Width;
                var dayWidth = labelWidth / colSpan;
                var firstDayCenterX = newCenterPoint.X - (colSpan - 1) * dayWidth / 2d;
                newCenterPoint.X = firstDayCenterX;
            }

            return newCenterPoint;
        }
        /// <summary>
        /// Remove resize mode views
        /// </summary>
        /// <param name="overlay">The resize mode overlay that triggered this, so we can remove it</param>
        private void EndResizeMode(View overlay)
        {
            _grid.Children.Remove(overlay);
            _grid.Children.Remove(_rightResizeHandle);
            _grid.Children.Remove(_rightResizeHandleDragger);
            _grid.Children.Remove(_leftResizeHandle);
            _grid.Children.Remove(_leftResizeHandleDragger);

            ((TappableView)overlay).Tapped -= HandleOverlayTapped;
            _rightResizeHandleDragger.Dragging -= HandleResizeDragging;
            _rightResizeHandleDragger.Dragged -= HandleResizeDragged;
            _rightResizeHandleDragger.DragCanceled -= HandleResizeCanceled;
            _leftResizeHandleDragger.Dragging -= HandleResizeDragging;
            _leftResizeHandleDragger.Dragged -= HandleResizeDragged;
            _leftResizeHandleDragger.DragCanceled -= HandleResizeCanceled;

            // Reset opacity
            foreach (var label in _labels)
            {
                label.Opacity = 1.0;
            }

            UnhighlightCells();

            _resizingEvent = null;
            _rightResizeHandle = null;
            _rightResizeHandleDragger = null;
            _leftResizeHandle = null;
            _leftResizeHandleDragger = null;
            _resizeRange = null;
        }
        /// <summary>
        /// Creates an invisible element directly on top of the provided drag handle visual
        /// which will actually process drag gestures.
        /// </summary>
        /// <remarks>
        /// The elements are set up as siblings with matching properties because a parental
        /// relationship would cause moving the visual to break the drag.
        /// This element is invisible because we don't want anything to actually follow the user's
        /// finger... we just want the drag to be rendered in controlled increments.
        /// </remarks>
        /// <param name="handle">A resize handle visual for which to create a drag element</param>
        /// <returns>The drag element</returns>
        private DraggableView CreateResizeHandleDraggerForVisual(View handle)
        {
            var dragger = new DraggableView();
            dragger.BackgroundColor = Color.Transparent;
            dragger.Dragging += HandleResizeDragging;
            dragger.Dragged += HandleResizeDragged;
            dragger.DragCanceled += HandleResizeCanceled;
            Grid.SetColumn(dragger, Grid.GetColumn(handle));
            Grid.SetRow(dragger, Grid.GetRow(handle));
            dragger.HeightRequest = handle.HeightRequest;
            dragger.WidthRequest = handle.WidthRequest;
            dragger.VerticalOptions = handle.VerticalOptions;
            dragger.HorizontalOptions = handle.HorizontalOptions;

            return dragger;
        }
        /// <summary>
        /// Creates overlay and tracking handles, highlights cells, and dims other events.
        /// </summary>
        /// <param name="ev">Event to resize</param>
        private void BeginResizeMode(Event ev)
        {
            _resizingEvent = ev;

            _resizeRange = new TimeRange(ev.Start, ev.End);

            // Create overlay to capture taps for dismissing resize mode
            //
            var overlay = new TappableView();
            Grid.SetRowSpan(overlay, _rows + 1);
            Grid.SetColumnSpan(overlay, _cols);
            overlay.BackgroundColor = Color.Transparent;

            overlay.Tapped += HandleOverlayTapped;

            _grid.Children.Add(overlay);

            // Dim everything but this event
            //
            foreach (var label in _labels.Where(l => l.BindingContext != _resizingEvent))
            {
                label.Opacity = 0.5;
            }

            HighlightCells(_resizingEvent.StartDate, _resizingEvent.EndDate);

            var cells = GetCellsForRange(_resizingEvent.StartDate, _resizingEvent.EndDate);
            var firstCell = cells.First();
            var lastCell = cells.Last();

            _leftResizeHandle = CreateResizeHandleVisual(Grid.GetColumn(firstCell), Grid.GetRow(firstCell), false);
            _grid.Children.Add(_leftResizeHandle);
            _rightResizeHandle = CreateResizeHandleVisual(Grid.GetColumn(lastCell), Grid.GetRow(lastCell), true);
            _grid.Children.Add(_rightResizeHandle);

            _leftResizeHandleDragger = CreateResizeHandleDraggerForVisual(_leftResizeHandle);
            _grid.Children.Add(_leftResizeHandleDragger);
            _rightResizeHandleDragger = CreateResizeHandleDraggerForVisual(_rightResizeHandle);
            _grid.Children.Add(_rightResizeHandleDragger);
        }
        /// <summary>
        /// Create an individual label corresponding to an event (possibly only part of the
        /// event) and place it on the grid.
        /// </summary>
        private DraggableView PlaceEventLabel(Event ev, int row, int col, int colSpan, Thickness margin = default(Thickness))
        {
            System.Diagnostics.Debug.WriteLine($"Placing {ev.Name} with a span of {colSpan}");

            var view = new DraggableView { BackgroundColor = Color.Blue, VerticalOptions = LayoutOptions.FillAndExpand };
            view.BindingContext = ev;

            var label = new Label();

            label.SetBinding<Event>(Label.TextProperty, e => e.Name);

            label.VerticalOptions = LayoutOptions.Fill;
            label.YAlign = TextAlignment.Center;
            label.FontSize = Device.GetNamedSize(NamedSize.Small, view);
            label.HorizontalOptions = LayoutOptions.FillAndExpand;

            view.Content = label;

            AutoStackGrid.SetMargin(view, margin);

            var container = GetEventContainerForRow(row + 1);

            container.AddChild(view, col, colSpan);

            var tapGesture = new TapGestureRecognizer();
            // First binding is to the "parent" context (i.e., ours, as opposed to the label's)
            //tapGesture.SetBinding(TapGestureRecognizer.CommandProperty, new Binding("EditEventCommand", BindingMode.Default, null, null, null, _vm));
            //tapGesture.SetBinding(TapGestureRecognizer.CommandParameterProperty, new Binding("."));

            // Activates resize mode instead of opening editor
            //
            tapGesture.Tapped += HandleEventTapped;

            view.GestureRecognizers.Add(tapGesture);

            view.Dragged += HandleDragged;
            view.DragStart += HandleDragStart;
            view.Dragging += HandleDragging;
            view.DragCanceled += HandleDragCanceled;

            _labels.Add(view);

            return view;
        }