diff --git a/src/Avalonia.Controls/DateTimePickers/DatePicker.cs b/src/Avalonia.Controls/DateTimePickers/DatePicker.cs index 7950bfaae1..6c74eb6b91 100644 --- a/src/Avalonia.Controls/DateTimePickers/DatePicker.cs +++ b/src/Avalonia.Controls/DateTimePickers/DatePicker.cs @@ -4,6 +4,7 @@ using Avalonia.Controls.Shapes; using Avalonia.Controls.Templates; using Avalonia.Data; using Avalonia.Interactivity; +using Avalonia.Layout; using System; using System.Collections.Generic; using System.Globalization; @@ -410,6 +411,11 @@ namespace Avalonia.Controls _popup.PlacementConstraintAdjustment = Primitives.PopupPositioning.PopupPositionerConstraintAdjustment.SlideY; _popup.IsOpen = true; + // Overlay popup hosts won't get measured until the next layout pass, but we need the + // template to be applied to `_presenter` now. Detect this case and force a layout pass. + if (!_presenter.IsMeasureValid) + (VisualRoot as ILayoutRoot)?.LayoutManager?.ExecuteInitialLayoutPass(); + var deltaY = _presenter.GetOffsetForPopup(); // The extra 5 px I think is related to default popup placement behavior diff --git a/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs b/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs index eac6d83074..0caba64758 100644 --- a/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs +++ b/src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs @@ -537,8 +537,11 @@ namespace Avalonia.Controls internal double GetOffsetForPopup() { + if (_monthSelector is null) + return 0; + var acceptDismissButtonHeight = _acceptButton != null ? _acceptButton.Bounds.Height : 41; - return -(MaxHeight - acceptDismissButtonHeight) / 2 - (_monthSelector!.ItemHeight / 2); + return -(MaxHeight - acceptDismissButtonHeight) / 2 - (_monthSelector.ItemHeight / 2); } } } diff --git a/src/Avalonia.Controls/DateTimePickers/TimePicker.cs b/src/Avalonia.Controls/DateTimePickers/TimePicker.cs index 4879749747..3aab49d556 100644 --- a/src/Avalonia.Controls/DateTimePickers/TimePicker.cs +++ b/src/Avalonia.Controls/DateTimePickers/TimePicker.cs @@ -3,6 +3,7 @@ using Avalonia.Controls.Primitives; using Avalonia.Controls.Shapes; using Avalonia.Controls.Templates; using Avalonia.Data; +using Avalonia.Layout; using System; using System.Globalization; @@ -267,6 +268,11 @@ namespace Avalonia.Controls _popup.PlacementConstraintAdjustment = Primitives.PopupPositioning.PopupPositionerConstraintAdjustment.SlideY; _popup.IsOpen = true; + // Overlay popup hosts won't get measured until the next layout pass, but we need the + // template to be applied to `_presenter` now. Detect this case and force a layout pass. + if (!_presenter.IsMeasureValid) + (VisualRoot as ILayoutRoot)?.LayoutManager?.ExecuteInitialLayoutPass(); + var deltaY = _presenter.GetOffsetForPopup(); // The extra 5 px I think is related to default popup placement behavior diff --git a/src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs b/src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs index 55bc1af3a7..30b6144388 100644 --- a/src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs +++ b/src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs @@ -256,8 +256,11 @@ namespace Avalonia.Controls internal double GetOffsetForPopup() { + if (_hourSelector is null) + return 0; + var acceptDismissButtonHeight = _acceptButton != null ? _acceptButton.Bounds.Height : 41; - return -(MaxHeight - acceptDismissButtonHeight) / 2 - (_hourSelector!.ItemHeight / 2); + return -(MaxHeight - acceptDismissButtonHeight) / 2 - (_hourSelector.ItemHeight / 2); } } }