diff --git a/src/SamplesApp/UITests.Shared/UITests.Shared.projitems b/src/SamplesApp/UITests.Shared/UITests.Shared.projitems
index 39b7d55ec8a3..376bb85c8667 100644
--- a/src/SamplesApp/UITests.Shared/UITests.Shared.projitems
+++ b/src/SamplesApp/UITests.Shared/UITests.Shared.projitems
@@ -1834,6 +1834,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
@@ -6099,6 +6103,9 @@
GridViewMultipleSelectionMode.xaml
+
+ Flyout_OverlayInputPassThroughElement.xaml
+
IconSourceElementTests.xaml
diff --git a/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Controls.Primitives/FlyoutBase.cs b/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Controls.Primitives/FlyoutBase.cs
index d9ca78ec0101..eb2840da1ca1 100644
--- a/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Controls.Primitives/FlyoutBase.cs
+++ b/src/Uno.UI/Generated/3.0.0.0/Microsoft.UI.Xaml.Controls.Primitives/FlyoutBase.cs
@@ -38,7 +38,7 @@ public bool ShouldConstrainToRootBounds
}
#endif
// Skipping already declared property Placement
-#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
+#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || false || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public global::Microsoft.UI.Xaml.DependencyObject OverlayInputPassThroughElement
{
@@ -148,7 +148,7 @@ public bool IsConstrainedToRootBounds
#endif
// Skipping already declared property IsOpenProperty
// Skipping already declared property LightDismissOverlayModeProperty
-#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
+#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || false || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public static global::Microsoft.UI.Xaml.DependencyProperty OverlayInputPassThroughElementProperty { get; } =
Microsoft.UI.Xaml.DependencyProperty.Register(
diff --git a/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.cs b/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.cs
index 62975a3f98ad..8c9f33880910 100644
--- a/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.cs
@@ -244,6 +244,15 @@ internal Brush LightDismissOverlayBackground
internal static DependencyProperty LightDismissOverlayBackgroundProperty { get; } =
DependencyProperty.Register("LightDismissOverlayBackground", typeof(Brush), typeof(FlyoutBase), new FrameworkPropertyMetadata(null));
+
+ internal static DependencyProperty OverlayInputPassThroughElementProperty { get; } =
+ DependencyProperty.Register("OverlayInputPassThroughElement", typeof(DependencyObject), typeof(FlyoutBase), new FrameworkPropertyMetadata(null));
+
+ public DependencyObject OverlayInputPassThroughElement
+ {
+ get { return (DependencyObject)GetValue(OverlayInputPassThroughElementProperty); }
+ set { SetValue(OverlayInputPassThroughElementProperty, value); }
+ }
///
/// Gets or sets whether a disabled control can receive focus.
diff --git a/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutPopupPanel.cs b/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutPopupPanel.cs
index b3fae3f3dc51..cdda2f9a57e0 100644
--- a/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutPopupPanel.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutPopupPanel.cs
@@ -1,11 +1,14 @@
#if !__UWP__
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Text;
using Uno.UI;
using Windows.Foundation;
+using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Microsoft.UI.Xaml.Controls.Primitives;
+using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
namespace Microsoft.UI.Xaml.Controls
@@ -35,6 +38,30 @@ public FlyoutBasePopupPanel(FlyoutBase flyout) : base(flyout._popup)
internal override FlyoutBase Flyout => _flyout;
protected override int PopupPlacementTargetMargin => 5;
+
+ protected override void OnPointerPressed(object sender, PointerRoutedEventArgs args)
+ {
+ base.OnPointerPressed(sender, args);
+
+ // Make sure we are the original source. We do not want to handle PointerPressed on the Popup itself.
+ if (args.OriginalSource == this)
+ {
+ if (Flyout.OverlayInputPassThroughElement is UIElement passThroughElement)
+ {
+ var (elementToBeHit, _) = VisualTreeHelper.SearchDownForTopMostElementAt(
+ args.GetCurrentPoint(null).Position,
+ passThroughElement.XamlRoot.VisualTree.RootElement,
+ VisualTreeHelper.DefaultGetTestability,
+ childrenFilter: elements => elements.Where(e => e != this));
+
+ var eventArgs = new PointerRoutedEventArgs(
+ new PointerEventArgs(args.GetCurrentPoint(null), args.KeyModifiers),
+ args.OriginalSource as UIElement);
+
+ elementToBeHit.OnPointerDown(eventArgs);
+ }
+ }
+ }
}
}
#endif
diff --git a/src/Uno.UI/UI/Xaml/Controls/Popup/PopupPanel.cs b/src/Uno.UI/UI/Xaml/Controls/Popup/PopupPanel.cs
index 70c2903ff583..606afda057e1 100644
--- a/src/Uno.UI/UI/Xaml/Controls/Popup/PopupPanel.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/Popup/PopupPanel.cs
@@ -243,7 +243,7 @@ private protected override void OnUnloaded()
// TODO: pointer handling should really go on PopupRoot. For now it's easier to put here because PopupRoot doesn't track open popups, and also we
// need to support native popups on Android that don't use PopupRoot.
- private void OnPointerPressed(object sender, PointerRoutedEventArgs args)
+ protected virtual void OnPointerPressed(object sender, PointerRoutedEventArgs args)
{
// Make sure we are the original source. We do not want to handle PointerPressed on the Popup itself.
if (args.OriginalSource == this && Popup is { } popup)
diff --git a/src/Uno.UI/UI/Xaml/Media/VisualTreeHelper.cs b/src/Uno.UI/UI/Xaml/Media/VisualTreeHelper.cs
index fb6bc81b9dd7..c94270911230 100644
--- a/src/Uno.UI/UI/Xaml/Media/VisualTreeHelper.cs
+++ b/src/Uno.UI/UI/Xaml/Media/VisualTreeHelper.cs
@@ -448,7 +448,7 @@ internal static (UIElement? element, Branch? stale) HitTest(
/// On skia: The absolute position relative to the window origin.
/// Everywhere else: The position relative to the parent (i.e. the position in parent coordinates).
///
- private static (UIElement? element, Branch? stale) SearchDownForTopMostElementAt(
+ internal static (UIElement? element, Branch? stale) SearchDownForTopMostElementAt(
Point position,
UIElement element,
GetHitTestability getVisibility,