1+ using CommunityToolkit . Maui . Core . Extensions ;
2+ using CommunityToolkit . Maui . Core . Views ;
3+ using Microsoft . Maui . Handlers ;
4+ using Microsoft . Maui . Platform ;
5+ using Microsoft . UI . Xaml ;
6+ using Microsoft . UI . Xaml . Controls ;
7+ using Microsoft . UI . Xaml . Controls . Primitives ;
8+ using Windows . UI . ViewManagement ;
9+
10+ namespace CommunityToolkit . Maui . Core . Handlers ;
11+
12+ public partial class PopupHandler : ElementHandler < IPopup , Popup >
13+ {
14+ /// <summary>
15+ /// Action that's triggered when the Popup is Dismissed.
16+ /// </summary>
17+ /// <param name="handler">An instance of <see cref="PopupHandler"/>.</param>
18+ /// <param name="view">An instance of <see cref="IPopup"/>.</param>
19+ /// <param name="result">The result that should return from this Popup.</param>
20+ public static void MapOnClosed ( PopupHandler handler , IPopup view , object ? result )
21+ {
22+ var window = view . GetWindow ( ) ;
23+ if ( window . Overlays . FirstOrDefault ( ) is IWindowOverlay popupOverlay )
24+ {
25+ window . RemoveOverlay ( popupOverlay ) ;
26+ }
27+
28+ view . HandlerCompleteTCS . TrySetResult ( ) ;
29+ handler . DisconnectHandler ( handler . PlatformView ) ;
30+ }
31+
32+ /// <summary>
33+ /// Action that's triggered when the Popup is Opened.
34+ /// </summary>
35+ /// <param name="handler">An instance of <see cref="PopupHandler"/>.</param>
36+ /// <param name="view">An instance of <see cref="IPopup"/>.</param>
37+ /// <param name="result">We don't need to provide the result parameter here.</param>
38+ public static void MapOnOpened ( PopupHandler handler , IPopup view , object ? result )
39+ {
40+ ArgumentNullException . ThrowIfNull ( view . Parent ) ;
41+ ArgumentNullException . ThrowIfNull ( handler . MauiContext ) ;
42+
43+ var parent = view . Parent . ToPlatform ( handler . MauiContext ) ;
44+ parent . IsHitTestVisible = false ;
45+ handler . PlatformView . XamlRoot = view . GetWindow ( ) . Content ? . Handler ? . MauiContext ? . GetPlatformWindow ( ) . Content . XamlRoot ?? throw new InvalidOperationException ( "Window Content cannot be null" ) ;
46+ handler . PlatformView . IsHitTestVisible = true ;
47+ handler . PlatformView . IsOpen = true ;
48+
49+ AddOverlayToWindow ( view . GetWindow ( ) ) ;
50+
51+ view . OnOpened ( ) ;
52+ }
53+
54+
55+ /// <summary>
56+ /// Action that's triggered when the Popup is dismissed by tapping outside of the Popup.
57+ /// </summary>
58+ /// <param name="handler">An instance of <see cref="PopupHandler"/>.</param>
59+ /// <param name="view">An instance of <see cref="IPopup"/>.</param>
60+ /// <param name="result">The result that should return from this Popup.</param>
61+ public static void MapOnDismissedByTappingOutsideOfPopup ( PopupHandler handler , IPopup view , object ? result )
62+ {
63+ view . OnDismissedByTappingOutsideOfPopup ( ) ;
64+ handler . DisconnectHandler ( handler . PlatformView ) ;
65+ }
66+
67+ /// <summary>
68+ /// Action that's triggered when the Popup <see cref="IPopup.Anchor"/> property changes.
69+ /// </summary>
70+ /// <param name="handler">An instance of <see cref="PopupHandler"/>.</param>
71+ /// <param name="view">An instance of <see cref="IPopup"/>.</param>
72+ public static void MapAnchor ( PopupHandler handler , IPopup view )
73+ {
74+ handler . PlatformView . SetAnchor ( view , handler . MauiContext ) ;
75+ }
76+
77+ /// <summary>
78+ /// Action that's triggered when the Popup <see cref="IPopup.CanBeDismissedByTappingOutsideOfPopup"/> property changes.
79+ /// </summary>
80+ /// <param name="handler">An instance of <see cref="PopupHandler"/>.</param>
81+ /// <param name="view">An instance of <see cref="IPopup"/>.</param>
82+ public static void MapCanBeDismissedByTappingOutsideOfPopup ( PopupHandler handler , IPopup view )
83+ {
84+ handler . PlatformView . IsLightDismissEnabled = view . CanBeDismissedByTappingOutsideOfPopup ;
85+ handler . PlatformView . LightDismissOverlayMode = LightDismissOverlayMode . Off ;
86+ }
87+
88+ /// <summary>
89+ /// Action that's triggered when the Popup <see cref="IPopup.Color"/> property changes.
90+ /// </summary>
91+ /// <param name="handler">An instance of <see cref="PopupHandler"/>.</param>
92+ /// <param name="view">An instance of <see cref="IPopup"/>.</param>
93+ public static void MapColor ( PopupHandler handler , IPopup view )
94+ {
95+ handler . PlatformView . SetColor ( view ) ;
96+ }
97+
98+ /// <summary>
99+ /// Action that's triggered when the Popup <see cref="IPopup.Size"/> property changes.
100+ /// </summary>
101+ /// <param name="handler">An instance of <see cref="PopupHandler"/>.</param>
102+ /// <param name="view">An instance of <see cref="IPopup"/>.</param>
103+ public static void MapSize ( PopupHandler handler , IPopup view )
104+ {
105+ handler . PlatformView . SetSize ( view , handler . MauiContext ) ;
106+ }
107+
108+ /// <inheritdoc/>
109+ protected override void DisconnectHandler ( Popup platformView )
110+ {
111+ if ( VirtualView . Parent is null )
112+ {
113+ return ;
114+ }
115+
116+ ArgumentNullException . ThrowIfNull ( VirtualView . Handler ? . MauiContext ) ;
117+ var parent = VirtualView . Parent . ToPlatform ( VirtualView . Handler . MauiContext ) ;
118+ parent . IsHitTestVisible = true ;
119+ platformView . IsOpen = false ;
120+ platformView . Closed -= OnClosed ;
121+ if ( MauiContext is not null )
122+ {
123+ MauiContext . GetPlatformWindow ( ) . SizeChanged -= OnSizeChanged ;
124+ }
125+ }
126+
127+ /// <inheritdoc/>
128+ protected override Popup CreatePlatformElement ( )
129+ {
130+ var popup = new Popup ( ) ;
131+ return popup ;
132+ }
133+
134+ /// <inheritdoc/>
135+ protected override void ConnectHandler ( Popup platformView )
136+ {
137+ platformView . Closed += OnClosed ;
138+ platformView . ConfigureControl ( VirtualView , MauiContext ) ;
139+ if ( MauiContext is not null )
140+ {
141+ MauiContext . GetPlatformWindow ( ) . SizeChanged += OnSizeChanged ;
142+ }
143+ base . ConnectHandler ( platformView ) ;
144+ }
145+
146+ static void AddOverlayToWindow ( IWindow window )
147+ {
148+ var uiSetting = new UISettings ( ) ;
149+ var backgroundColor = uiSetting . GetColorValue ( UIColorType . Background ) . ToColor ( ) ;
150+ window . AddOverlay ( new PopupOverlay ( window , backgroundColor . IsDark ( )
151+ ? Color . FromRgba ( 0 , 0 , 0 , 153 )
152+ : Color . FromRgba ( 255 , 255 , 255 , 153 ) ) ) ; // 60% Opacity
153+ }
154+
155+ void OnClosed ( object ? sender , object e )
156+ {
157+ if ( ! PlatformView . IsOpen && VirtualView . CanBeDismissedByTappingOutsideOfPopup )
158+ {
159+ VirtualView . Handler ? . Invoke ( nameof ( IPopup . OnDismissedByTappingOutsideOfPopup ) ) ;
160+ }
161+ }
162+
163+ void OnSizeChanged ( object ? sender , WindowSizeChangedEventArgs e )
164+ {
165+ if ( VirtualView is not null )
166+ {
167+ PopupExtensions . SetSize ( PlatformView , VirtualView , MauiContext ) ;
168+ PopupExtensions . SetLayout ( PlatformView , VirtualView , MauiContext ) ;
169+ }
170+ }
171+ }
0 commit comments