Skip to content

Commit a185bf1

Browse files
authored
Refines MAUI Dialog Layout and Active State Management (#3390)
* check to see if dialog page is attached to window * fix race condition in dialog service navigation state updates Ensures that PageNavigationSource and IsActive state updates are deferred until the dialog has been pushed by using ContinueWith on the asynchronous ConfigureLayout call. This prevents state updates from executing before the modal is actually displayed. * fixed window deactivation state * fix dialog mask layout and tap gesture reliability Replaces the root AbsoluteLayout in DialogContainerPage with a Grid. This ensures the background mask fills the screen naturally without needing proportional sizing or explicit WidthRequest/HeightRequest bindings, which were causing tap gestures to fail on some MAUI platforms.
1 parent dee8c41 commit a185bf1

File tree

3 files changed

+33
-27
lines changed

3 files changed

+33
-27
lines changed

src/Maui/Prism.Maui/Dialogs/DialogContainerPage.cs

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,12 @@ public virtual async Task DoPop(Page currentPage)
8989
/// <returns>The content layout for the dialog container page.</returns>
9090
protected virtual View GetContentLayout(Page currentPage, View dialogView, bool hideOnBackgroundTapped, ICommand dismissCommand, IDialogParameters parameters)
9191
{
92-
var overlay = new AbsoluteLayout();
92+
// Use a Grid so the mask fills the page naturally without needing
93+
// AbsoluteLayout proportional sizing, which conflicted with the
94+
// WidthRequest/HeightRequest bindings and caused tap gestures on
95+
// the mask to not fire reliably across MAUI platforms.
96+
var overlay = new Grid();
97+
9398
var popupContainer = new DialogContainerView
9499
{
95100
IsPopupContent = true,
@@ -118,20 +123,21 @@ protected virtual View GetContentLayout(Page currentPage, View dialogView, bool
118123
source: this));
119124
}
120125

121-
AbsoluteLayout.SetLayoutFlags(popupContainer, AbsoluteLayoutFlags.PositionProportional);
122-
var popupBounds = DialogLayout.GetLayoutBounds(dialogView);
123-
AbsoluteLayout.SetLayoutBounds(popupContainer, popupBounds);
124-
125-
var useMask = DialogLayout.GetUseMask(popupContainer.Content) ?? true;
126+
var useMask = DialogLayout.GetUseMask(dialogView) ?? true;
126127
if (useMask)
127128
{
128129
var mask = GetMask(currentPage, dialogView, hideOnBackgroundTapped, dismissCommand);
129-
AbsoluteLayout.SetLayoutFlags(mask, AbsoluteLayoutFlags.All);
130-
AbsoluteLayout.SetLayoutBounds(mask, new Rect(0, 0, 1, 1));
131130
overlay.Children.Add(mask);
132131
}
133132

134-
overlay.Children.Add(popupContainer);
133+
// Keep an AbsoluteLayout for the popup so LayoutBounds positioning still works
134+
var popupArea = new AbsoluteLayout();
135+
AbsoluteLayout.SetLayoutFlags(popupContainer, AbsoluteLayoutFlags.PositionProportional);
136+
var popupBounds = DialogLayout.GetLayoutBounds(dialogView);
137+
AbsoluteLayout.SetLayoutBounds(popupContainer, popupBounds);
138+
popupArea.Children.Add(popupContainer);
139+
140+
overlay.Children.Add(popupArea);
135141
return overlay;
136142
}
137143

@@ -146,29 +152,18 @@ protected virtual View GetContentLayout(Page currentPage, View dialogView, bool
146152
private View GetMask(Page currentPage, View dialogView, bool hideOnBackgroundTapped, ICommand dismissCommand)
147153
{
148154
View mask = DialogLayout.GetMask(dialogView);
149-
var reference = currentPage.GetParentWindow().Page;
150155
if (mask is null)
151156
{
152157
Style overlayStyle = GetOverlayStyle(dialogView, currentPage);
153158

154159
mask = new BoxView
155160
{
156161
Style = overlayStyle,
157-
//HeightRequest = reference.Height,
158-
//WidthRequest = reference.Width
159162
};
160163
}
161164

162-
mask.SetBinding(WidthRequestProperty, new Binding
163-
{
164-
Path = nameof(Width),
165-
Source = reference
166-
});
167-
mask.SetBinding(HeightRequestProperty, new Binding
168-
{
169-
Path = nameof(Height),
170-
Source = reference
171-
});
165+
// No explicit WidthRequest/HeightRequest needed — the Grid parent
166+
// sizes the mask to fill the page automatically.
172167

173168
if (hideOnBackgroundTapped)
174169
{

src/Maui/Prism.Maui/Dialogs/DialogServiceBase.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,23 @@ async Task DialogAware_RequestClose(IDialogResult outResult)
9797

9898
var dismissCommand = new DelegateCommand(() => dialogAware.RequestClose.Invoke(), dialogAware.CanCloseDialog);
9999

100+
// ConfigureLayout is async (it awaits DoPush internally). Since ShowDialog is void,
101+
// we use ContinueWith to defer post-push work until the modal is actually displayed.
102+
// Without this, NavigationSource resets and IsActive updates race ahead of the push.
100103
PageNavigationService.NavigationSource = PageNavigationSource.DialogService;
101-
dialogModal.ConfigureLayout(currentPage, view, closeOnBackgroundTapped, dismissCommand, parameters);
102-
PageNavigationService.NavigationSource = PageNavigationSource.Device;
104+
dialogModal.ConfigureLayout(currentPage, view, closeOnBackgroundTapped, dismissCommand, parameters)
105+
.ContinueWith(t =>
106+
{
107+
if (t.IsFaulted)
108+
{
109+
callback.Invoke(t.Exception?.InnerException ?? t.Exception);
110+
return;
111+
}
103112

104-
MvvmHelpers.InvokeViewAndViewModelAction<IActiveAware>(currentPage, aa => aa.IsActive = false);
105-
MvvmHelpers.InvokeViewAndViewModelAction<IActiveAware>(view, aa => aa.IsActive = true);
113+
PageNavigationService.NavigationSource = PageNavigationSource.Device;
114+
MvvmHelpers.InvokeViewAndViewModelAction<IActiveAware>(currentPage, aa => aa.IsActive = false);
115+
MvvmHelpers.InvokeViewAndViewModelAction<IActiveAware>(view, aa => aa.IsActive = true);
116+
}, TaskScheduler.FromCurrentSynchronizationContext());
106117
}
107118
catch (Exception ex)
108119
{

src/Maui/Prism.Maui/Navigation/PrismWindow.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ protected override void OnActivated()
105105
protected override void OnDeactivated()
106106
{
107107
IsActive = false;
108-
MvvmHelpers.InvokeViewAndViewModelAction<IActiveAware>(CurrentPage, x => x.IsActive = true);
108+
MvvmHelpers.InvokeViewAndViewModelAction<IActiveAware>(CurrentPage, x => x.IsActive = false);
109109
}
110110

111111
/// <summary>

0 commit comments

Comments
 (0)