diff --git a/src/SamplesApp/SamplesApp.UITests/ScreenshotInfo.cs b/src/SamplesApp/SamplesApp.UITests/ScreenshotInfo.cs
index 009839a9cb14..5debdcdb9725 100644
--- a/src/SamplesApp/SamplesApp.UITests/ScreenshotInfo.cs
+++ b/src/SamplesApp/SamplesApp.UITests/ScreenshotInfo.cs
@@ -23,6 +23,11 @@ public ScreenshotInfo(FileInfo file, string stepName)
public static implicit operator ScreenshotInfo(FileInfo fi) => new ScreenshotInfo(fi, fi.Name);
public Bitmap GetBitmap() => _bitmap ??= new Bitmap(File.FullName);
+
+ public int Width => GetBitmap().Width;
+
+ public int Height => GetBitmap().Height;
+
public void Dispose()
{
_bitmap?.Dispose();
diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/FlyoutTests/UnoSamples_Tests.Flyout.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/FlyoutTests/UnoSamples_Tests.Flyout.cs
index e9821c6b3bf0..4b753f037b42 100644
--- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/FlyoutTests/UnoSamples_Tests.Flyout.cs
+++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/FlyoutTests/UnoSamples_Tests.Flyout.cs
@@ -233,5 +233,20 @@ public void Flyout_Namescope()
_app.FastTap(closeButton);
}
+
+ [Test]
+ [AutoRetry]
+ public void Flyout_ShowAt_Window_Content()
+ {
+ Run("UITests.Windows_UI_Xaml_Controls.FlyoutTests.Flyout_ShowAt_Window_Content");
+
+ var windowButton = _app.Marked("WindowButton");
+
+ _app.WaitForElement(windowButton);
+ _app.FastTap(windowButton);
+
+ using var result = TakeScreenshot("Result", ignoreInSnapshotCompare: true);
+ ImageAssert.HasColorAt(result, result.Width / 2, 150, Color.Red);
+ }
}
}
diff --git a/src/SamplesApp/UITests.Shared/UITests.Shared.projitems b/src/SamplesApp/UITests.Shared/UITests.Shared.projitems
index 720969906bb1..0aaa4ca4bfa9 100644
--- a/src/SamplesApp/UITests.Shared/UITests.Shared.projitems
+++ b/src/SamplesApp/UITests.Shared/UITests.Shared.projitems
@@ -1445,6 +1445,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
@@ -5552,6 +5556,9 @@
Flyout_Namescope.xaml
+
+ Flyout_ShowAt_Window_Content.xaml
+
Flyout_TemplatedParent.xaml
diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Flyout/Flyout_ShowAt_Window_Content.xaml b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Flyout/Flyout_ShowAt_Window_Content.xaml
new file mode 100644
index 000000000000..052c95e6fe93
--- /dev/null
+++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Flyout/Flyout_ShowAt_Window_Content.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Flyout/Flyout_ShowAt_Window_Content.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Flyout/Flyout_ShowAt_Window_Content.xaml.cs
new file mode 100644
index 000000000000..9f60c3b24371
--- /dev/null
+++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Flyout/Flyout_ShowAt_Window_Content.xaml.cs
@@ -0,0 +1,49 @@
+using Uno.UI.Samples.Controls;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Media;
+
+// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
+
+namespace UITests.Windows_UI_Xaml_Controls.FlyoutTests
+{
+ ///
+ /// An empty page that can be used on its own or navigated to within a Frame.
+ ///
+ [Sample]
+ public sealed partial class Flyout_ShowAt_Window_Content : Page
+ {
+ public Flyout_ShowAt_Window_Content()
+ {
+ this.InitializeComponent();
+ }
+
+ private void ButtonButton_Click(object sender, RoutedEventArgs e)
+ {
+ Windows.UI.Xaml.Controls.Flyout flyout = new Windows.UI.Xaml.Controls.Flyout();
+ flyout.Content =
+ new Border()
+ {
+ Width = 300,
+ Height = 300,
+ Background = new SolidColorBrush(Windows.UI.Colors.Red),
+ };
+
+ flyout.ShowAt((Button)sender);
+ }
+
+ private void WindowButton_Click(object sender, RoutedEventArgs e)
+ {
+ Windows.UI.Xaml.Controls.Flyout flyout = new Windows.UI.Xaml.Controls.Flyout();
+ flyout.Content =
+ new Border()
+ {
+ Width = 300,
+ Height = 300,
+ Background = new SolidColorBrush(Windows.UI.Colors.Red),
+ };
+
+ flyout.ShowAt(global::Windows.UI.Xaml.Window.Current.Content as FrameworkElement);
+ }
+ }
+}
diff --git a/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.cs b/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.cs
index a21f8e41a038..782189936ae4 100644
--- a/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.cs
@@ -325,7 +325,10 @@ private protected virtual void ShowAtCore(FrameworkElement placementTarget, Flyo
throw new ArgumentException("Invalid flyout position");
}
- // UNO TODO: clamp position within contentRect
+ var visibleBounds = ApplicationView.GetForCurrentView().VisibleBounds;
+ positionValue = new Point(
+ positionValue.X.Clamp(visibleBounds.Left, visibleBounds.Right),
+ positionValue.Y.Clamp(visibleBounds.Top, visibleBounds.Bottom));
SetTargetPosition(positionValue);
}
diff --git a/src/Uno.UI/UI/Xaml/Controls/Popup/PlacementPopupPanel.cs b/src/Uno.UI/UI/Xaml/Controls/Popup/PlacementPopupPanel.cs
index 32a5e0a7b949..e6d1b1cd7f9c 100644
--- a/src/Uno.UI/UI/Xaml/Controls/Popup/PlacementPopupPanel.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/Popup/PlacementPopupPanel.cs
@@ -285,6 +285,48 @@ ref controlYPos
{
this.Log().LogDebug($"Calculated placement, finalRect={finalRect}");
}
+
+ // Ensure the popup is not positioned fully beyond visible bounds.
+ // This can happen for example when the user is trying to show a flyout at
+ // Window.Current.Content - which will match Top position, which would be outside
+ // the visible bounds (negative Y).
+
+ if (finalRect.Bottom < visibleBounds.Top)
+ {
+ finalRect = new Rect(
+ finalRect.Left,
+ visibleBounds.Top,
+ finalRect.Width,
+ finalRect.Height);
+ }
+
+ if (finalRect.Top > visibleBounds.Bottom)
+ {
+ finalRect = new Rect(
+ finalRect.Left,
+ visibleBounds.Bottom - finalRect.Height,
+ finalRect.Width,
+ finalRect.Height);
+ }
+
+ if (finalRect.Right < visibleBounds.Left)
+ {
+ finalRect = new Rect(
+ visibleBounds.Left,
+ finalRect.Top,
+ finalRect.Width,
+ finalRect.Height);
+ }
+
+ if (finalRect.Left > visibleBounds.Right)
+ {
+ finalRect = new Rect(
+ visibleBounds.Right - finalRect.Width,
+ finalRect.Top,
+ finalRect.Width,
+ finalRect.Height);
+ }
+
return finalRect;
}
diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextVisual.skia.cs b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextVisual.skia.cs
index 9fc64caf0a01..916180275c00 100644
--- a/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextVisual.skia.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextVisual.skia.cs
@@ -139,7 +139,7 @@ public void UpdateForeground()
internal override void Render(SKSurface surface)
{
- if (!string.IsNullOrEmpty(_owner.Text))
+ if (!string.IsNullOrEmpty(_owner.Text) && Size != default)
{
UpdateForeground();