diff --git a/src/Uno.UI/UI/Xaml/DragDrop/DropUITarget.cs b/src/Uno.UI/UI/Xaml/DragDrop/DropUITarget.cs index ae7b17354d86..f5473c5885c7 100644 --- a/src/Uno.UI/UI/Xaml/DragDrop/DropUITarget.cs +++ b/src/Uno.UI/UI/Xaml/DragDrop/DropUITarget.cs @@ -20,17 +20,19 @@ namespace Windows.UI.Xaml { internal class DropUITarget : ICoreDropOperationTarget { - private static readonly GetHitTestability _getDropHitTestability = elt => + private static GetHitTestability? _getDropHitTestability; + private static GetHitTestability GetDropHitTestability => _getDropHitTestability ??= (elt => { var visiblity = elt.GetHitTestVisibility(); return visiblity switch { - HitTestability.Collapsed => HitTestability.Collapsed, - _ when !elt.AllowDrop => HitTestability.Invisible, - _ => visiblity + HitTestability.Collapsed => (HitTestability.Collapsed, _getDropHitTestability!), + // Once we reached an element that AllowDrop, we only validate the hit testability for its children + _ when elt.AllowDrop => (visiblity, VisualTreeHelper.DefaultGetTestability), + _ => (HitTestability.Invisible, _getDropHitTestability!) }; - }; - + }); + // Note: As drag events are routed (so they may be received by multiple elements), we might not have an entry for each drop targets. // We will instead have entry only for leaf (a.k.a. OriginalSource). @@ -124,7 +126,7 @@ public IAsyncOperation DropAsync(CoreDragInfo dragInfo) { var target = VisualTreeHelper.HitTest( dragInfo.Position, - getTestability: _getDropHitTestability, + getTestability: GetDropHitTestability, isStale: elt => elt.IsDragOver(dragInfo.SourceId)); // First raise the drag leave event on stale branch if any. diff --git a/src/Uno.UI/UI/Xaml/HitTestability.cs b/src/Uno.UI/UI/Xaml/HitTestability.cs index cd83da2fb1c6..caeea579f9be 100644 --- a/src/Uno.UI/UI/Xaml/HitTestability.cs +++ b/src/Uno.UI/UI/Xaml/HitTestability.cs @@ -1,9 +1,11 @@ -using System; +#nullable enable + +using System; using System.Linq; namespace Windows.UI.Xaml { - internal delegate HitTestability GetHitTestability(UIElement element); + internal delegate (HitTestability elementTestability, GetHitTestability childrenGetHitTestability) GetHitTestability(UIElement element); internal enum HitTestability { diff --git a/src/Uno.UI/UI/Xaml/Media/VisualTreeHelper.cs b/src/Uno.UI/UI/Xaml/Media/VisualTreeHelper.cs index 4e9062936790..854fe869ec7d 100644 --- a/src/Uno.UI/UI/Xaml/Media/VisualTreeHelper.cs +++ b/src/Uno.UI/UI/Xaml/Media/VisualTreeHelper.cs @@ -250,7 +250,11 @@ internal static IReadOnlyList<_View> ClearChildren(UIElement view) #endif } - private static readonly GetHitTestability _defaultGetTestability = elt => elt.GetHitTestVisibility(); + internal static readonly GetHitTestability DefaultGetTestability; + static VisualTreeHelper() + { + DefaultGetTestability = elt => (elt.GetHitTestVisibility(), DefaultGetTestability); + } internal static (UIElement? element, Branch? stale) HitTest( Point position, @@ -267,7 +271,7 @@ internal static (UIElement? element, Branch? stale) HitTest( #endif if (Window.Current.RootElement is UIElement root) { - return SearchDownForTopMostElementAt(position, root, getTestability ?? _defaultGetTestability, isStale); + return SearchDownForTopMostElementAt(position, root, getTestability ?? DefaultGetTestability, isStale); } return default; @@ -281,7 +285,8 @@ private static (UIElement? element, Branch? stale) SearchDownForTopMostElementAt Func, IEnumerable>? childrenFilter = null) { var stale = default(Branch?); - var elementHitTestVisibility = getVisibility(element); + HitTestability elementHitTestVisibility; + (elementHitTestVisibility, getVisibility) = getVisibility(element); #if TRACE_HIT_TESTING using var _ = SET_TRACE_SUBJECT(element); diff --git a/src/Uno.UI/UI/Xaml/UIElement.netstd.cs b/src/Uno.UI/UI/Xaml/UIElement.netstd.cs index 63779bf17449..cba7fae8b99d 100644 --- a/src/Uno.UI/UI/Xaml/UIElement.netstd.cs +++ b/src/Uno.UI/UI/Xaml/UIElement.netstd.cs @@ -46,7 +46,11 @@ public partial class UIElement : DependencyObject internal bool IsLoading { get; private set; } #endif - private protected int Depth { get; private set; } = int.MinValue; + /// + /// Gets the element depth in the visual tree. + /// ** WARNING** This is set before the FrameworkElement loading event and cleared on unload. + /// + internal int Depth { get; private set; } = int.MinValue; internal static void LoadingRootElement(UIElement visualTreeRoot) => visualTreeRoot.OnElementLoading(1);