[iOS] Fix: invoke MediaPicker completion handler after DismissViewController#34250
Conversation
|
Hey there @@yuriikyry4enko! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
|
@yuriikyry4enko thanks for this! Are you sure this isn't already working for .NET 10? Because a lot changed for the MediaPicker in .NET 10. |
I was able to reproduce the issue on a physical device — tested on iPhone 16, iOS 26.2.1. Attaching a sample project for reference. |
jfversluis
left a comment
There was a problem hiding this comment.
Multi-Model Code Review — PR #34250
Reviewed by 3 independent AI models (Claude Sonnet 4.5, GPT-5.2, Gemini 3 Pro) via Copilot CLI
Is this still needed?
YES. The file MediaPicker.ios.cs has identical SHA on both main and net10.0 branches. The bug is not fixed anywhere.
Is the fix correct?
All 3 models agree: YES, the core approach is correct. Moving CompletedHandler into the DismissViewController completion callback is the textbook iOS UIKit pattern — it ensures the picker is fully dismissed before resolving the TaskCompletionSource, which prevents subsequent UI presentations (like DisplayAlert) from silently failing.
The PHPickerViewController path (iOS 14+, most common) is clean and correct as-is.
Issues Found (consensus across all 3 models)
1. 🚨 Double-dismiss on UIImagePickerController path
All 3 models independently flagged this. After this PR, the sequence is:
FinishedPickingMediacallsDismissViewController(true, () => CompletedHandler?.Invoke(info))- Dismiss completes →
CompletedHandlerruns CompletedHandlercallsawait picker.DismissViewControllerAsync(true)— second dismiss on already-dismissed VC
The CompletedHandler lambda (~line 140-144) still contains its own dismiss call:
CompletedHandler = async info =>
{
GetFileResult(info, tcs, options);
await picker.DismissViewControllerAsync(true); // ← redundant, VC already dismissed by delegate
}Risk: Low (UIKit typically no-ops on already-dismissed VCs), but it's a code smell that could produce console warnings. Recommendation: Remove await picker.DismissViewControllerAsync(true) from the CompletedHandler since the delegate now handles dismissal.
2. ⚠️ Whitespace inconsistency (tabs vs spaces)
The FinishedPickingMedia method changed from tab indentation to space indentation, and DidFinishPicking has mixed tabs/spaces. Please run dotnet format or manually align to match the existing file style before merge.
Things That Look Good
- ✅ The
var capturedpattern inDidFinishPickingis good defensive coding — captures and sanitizes results before the async callback - ✅ No threading concerns — all paths run on the main thread via UIKit completion callbacks
- ✅
tcs.TrySetResultis thread-safe - ✅ The slight delay from waiting for dismiss animation (~400ms) is actually desirable — it's what prevents the race condition
Summary
The fix is the right approach and resolves the core issue. Please address:
- Remove the redundant dismiss in the
UIImagePickerControllerCompletedHandler(~line 143) - Fix whitespace to match existing file style
After those changes, this is good to merge. 👍
@dotnet-policy-service agree
@dotnet-policy-service agree |
jfversluis
left a comment
There was a problem hiding this comment.
Thanks for addressing the double-dismiss issue! 👍
One remaining thing: the lambda at line ~140 still has async but no longer contains any await:
CompletedHandler = async info =>
{
GetFileResult(info, tcs, options);
}This will trigger compiler warning CS1998 ("This async method lacks 'await' operators and will run synchronously"). Since the await picker.DismissViewControllerAsync(true) was removed, the async keyword should be removed too:
CompletedHandler = info =>
{
GetFileResult(info, tcs, options);
}|
/azp run maui-pr |
|
Azure Pipelines successfully started running 1 pipeline(s). |
…ss handling
Three fixes for the dogfooding infrastructure:
1. **Workflow trigger**: Reverted dogfood-comment.yml from check_run to
pull_request_target trigger. Azure DevOps check runs never populate the
pull_requests[] array, so the check_run-based condition was always false
and the workflow never ran.
2. **AzDO direct fallback**: Added Azure DevOps API as a fallback when
GitHub Checks API doesn't return build info. Queries
refs/pull/{PR}/merge branch directly to find completed builds.
3. **In-progress build detection**: Added detection for builds that are
currently running. Shows a clear message telling users to wait instead
of a generic 'no build found' error. Also warns when a newer build is
in progress but older artifacts are available.
Additional improvements:
- Build ID validation (numeric check) to prevent URL injection
- PR number validation in bash script
- Protection against set -e crashes on invalid jq input
- Better error messages for all failure scenarios
Tested locally with multiple real PRs (#34216, #34250, #99999999) across
both scripts, verifying: successful builds, in-progress builds, error
handling, and input validation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ss handling (#34259) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Description Three fixes for the dogfooding infrastructure that was merged in #33198 but never worked correctly: ### 1. Workflow trigger fix (`dogfood-comment.yml`) The workflow was changed from `pull_request_target` to `check_run` trigger in #33198, but Azure DevOps check runs **never populate the `pull_requests[]` array**. This means `github.event.check_run.pull_requests[0] != null` was **always false**, and the workflow never ran. **Fix**: Reverted to `pull_request_target` trigger with a comment explaining why `check_run` does not work. ### 2. AzDO direct fallback (both scripts) When the GitHub Checks API does not return build info (which can happen for merge commits or in certain timing windows), the scripts now fall back to querying the Azure DevOps API directly using `refs/pull/{PR}/merge` branch name. This approach is modeled after the working implementation in [maui-version](https://github.com/jfversluis/maui-version). ### 3. In-progress build detection (both scripts) When no completed build is found, the scripts now query AzDO for builds with `status in ("inProgress", "notStarted", "postponed")`. Instead of the generic "no build found" error, users now see: - **Build in progress**: "A build is currently in progress. Please wait for it to complete." - **Stale artifacts**: When an older build has artifacts but a newer build is running, warns users ### Additional improvements - Build ID numeric validation to prevent URL injection - PR number validation in bash script - Protection against `set -e` crashes on invalid `jq` input - Better error messages for all failure scenarios ## Testing Tested locally with multiple real PRs across both scripts: - ✅ PR #34216 (completed, successful) - both scripts find build and apply artifacts - ✅ PR #34250 (in-progress build) - correctly finds existing artifacts with warning - ✅ PR #99999999 (non-existent) - proper error handling - ✅ Invalid PR number ("abc") - input validation works - ✅ Multi-model code review (Claude Sonnet 4.5, GPT-5.1, Gemini 3 Pro) - all findings addressed Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2c6b032 to
50ab7c3
Compare
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34250Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34250" |
50ab7c3 to
2b3bc28
Compare
…ss handling (#34259) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Description Three fixes for the dogfooding infrastructure that was merged in #33198 but never worked correctly: ### 1. Workflow trigger fix (`dogfood-comment.yml`) The workflow was changed from `pull_request_target` to `check_run` trigger in #33198, but Azure DevOps check runs **never populate the `pull_requests[]` array**. This means `github.event.check_run.pull_requests[0] != null` was **always false**, and the workflow never ran. **Fix**: Reverted to `pull_request_target` trigger with a comment explaining why `check_run` does not work. ### 2. AzDO direct fallback (both scripts) When the GitHub Checks API does not return build info (which can happen for merge commits or in certain timing windows), the scripts now fall back to querying the Azure DevOps API directly using `refs/pull/{PR}/merge` branch name. This approach is modeled after the working implementation in [maui-version](https://github.com/jfversluis/maui-version). ### 3. In-progress build detection (both scripts) When no completed build is found, the scripts now query AzDO for builds with `status in ("inProgress", "notStarted", "postponed")`. Instead of the generic "no build found" error, users now see: - **Build in progress**: "A build is currently in progress. Please wait for it to complete." - **Stale artifacts**: When an older build has artifacts but a newer build is running, warns users ### Additional improvements - Build ID numeric validation to prevent URL injection - PR number validation in bash script - Protection against `set -e` crashes on invalid `jq` input - Better error messages for all failure scenarios ## Testing Tested locally with multiple real PRs across both scripts: - ✅ PR #34216 (completed, successful) - both scripts find build and apply artifacts - ✅ PR #34250 (in-progress build) - correctly finds existing artifacts with warning - ✅ PR #99999999 (non-existent) - proper error handling - ✅ Invalid PR number ("abc") - input validation works - ✅ Multi-model code review (Claude Sonnet 4.5, GPT-5.1, Gemini 3 Pro) - all findings addressed Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…troller (#34250) ### Description of Change On iOS, `CompletedHandler` was being invoked **before** `DismissViewController` had finished animating. This means any code running in the handler — such as showing an alert, opening a modal, or triggering navigation — would fire while the picker view controller was still visible and attached to the view hierarchy. iOS UIKit requires the presenting view controller to be fully visible and attached before presenting any new UI (alerts, modals, sheets). If you attempt to present something while a dismiss animation is still in progress, UIKit silently drops the presentation or throws a warning, resulting in: - `DisplayAlert` / `DisplayActionSheet` not appearing after picking an image - Custom modal dialogs not showing up - Any `await`-based UI call after `PickPhotoAsync` / `PickVideoAsync` silently failing on iOS, while working fine on Android The root cause is that `DismissViewController(animated:completion:)` accepts a completion callback precisely for this purpose — to run logic **after** the animation finishes — but the original code passed `null` and called the handler immediately after, creating a race condition. **Fix:** Moved all `CompletedHandler` invocations into the `completion` callback of `DismissViewController` across three call sites: - `UIImagePickerControllerDelegate.FinishedPickingMedia` - `UIImagePickerControllerDelegate.Canceled` - `PHPickerViewControllerDelegate.DidFinishPicking` ### Issues Fixed Fixes #21996 ### Testing Tested on a physical iOS device. - Opened image picker via `MediaPicker.PickPhotoAsync()` - After selecting an image, called `DisplayAlert` in the continuation - **Before fix:** alert did not appear after dismissing the picker - **After fix:** alert appears correctly after the picker is fully dismissed
…troller (#34250) ### Description of Change On iOS, `CompletedHandler` was being invoked **before** `DismissViewController` had finished animating. This means any code running in the handler — such as showing an alert, opening a modal, or triggering navigation — would fire while the picker view controller was still visible and attached to the view hierarchy. iOS UIKit requires the presenting view controller to be fully visible and attached before presenting any new UI (alerts, modals, sheets). If you attempt to present something while a dismiss animation is still in progress, UIKit silently drops the presentation or throws a warning, resulting in: - `DisplayAlert` / `DisplayActionSheet` not appearing after picking an image - Custom modal dialogs not showing up - Any `await`-based UI call after `PickPhotoAsync` / `PickVideoAsync` silently failing on iOS, while working fine on Android The root cause is that `DismissViewController(animated:completion:)` accepts a completion callback precisely for this purpose — to run logic **after** the animation finishes — but the original code passed `null` and called the handler immediately after, creating a race condition. **Fix:** Moved all `CompletedHandler` invocations into the `completion` callback of `DismissViewController` across three call sites: - `UIImagePickerControllerDelegate.FinishedPickingMedia` - `UIImagePickerControllerDelegate.Canceled` - `PHPickerViewControllerDelegate.DidFinishPicking` ### Issues Fixed Fixes #21996 ### Testing Tested on a physical iOS device. - Opened image picker via `MediaPicker.PickPhotoAsync()` - After selecting an image, called `DisplayAlert` in the continuation - **Before fix:** alert did not appear after dismissing the picker - **After fix:** alert appears correctly after the picker is fully dismissed
…troller (#34250) ### Description of Change On iOS, `CompletedHandler` was being invoked **before** `DismissViewController` had finished animating. This means any code running in the handler — such as showing an alert, opening a modal, or triggering navigation — would fire while the picker view controller was still visible and attached to the view hierarchy. iOS UIKit requires the presenting view controller to be fully visible and attached before presenting any new UI (alerts, modals, sheets). If you attempt to present something while a dismiss animation is still in progress, UIKit silently drops the presentation or throws a warning, resulting in: - `DisplayAlert` / `DisplayActionSheet` not appearing after picking an image - Custom modal dialogs not showing up - Any `await`-based UI call after `PickPhotoAsync` / `PickVideoAsync` silently failing on iOS, while working fine on Android The root cause is that `DismissViewController(animated:completion:)` accepts a completion callback precisely for this purpose — to run logic **after** the animation finishes — but the original code passed `null` and called the handler immediately after, creating a race condition. **Fix:** Moved all `CompletedHandler` invocations into the `completion` callback of `DismissViewController` across three call sites: - `UIImagePickerControllerDelegate.FinishedPickingMedia` - `UIImagePickerControllerDelegate.Canceled` - `PHPickerViewControllerDelegate.DidFinishPicking` ### Issues Fixed Fixes #21996 ### Testing Tested on a physical iOS device. - Opened image picker via `MediaPicker.PickPhotoAsync()` - After selecting an image, called `DisplayAlert` in the continuation - **Before fix:** alert did not appear after dismissing the picker - **After fix:** alert appears correctly after the picker is fully dismissed
…troller (dotnet#34250) ### Description of Change On iOS, `CompletedHandler` was being invoked **before** `DismissViewController` had finished animating. This means any code running in the handler — such as showing an alert, opening a modal, or triggering navigation — would fire while the picker view controller was still visible and attached to the view hierarchy. iOS UIKit requires the presenting view controller to be fully visible and attached before presenting any new UI (alerts, modals, sheets). If you attempt to present something while a dismiss animation is still in progress, UIKit silently drops the presentation or throws a warning, resulting in: - `DisplayAlert` / `DisplayActionSheet` not appearing after picking an image - Custom modal dialogs not showing up - Any `await`-based UI call after `PickPhotoAsync` / `PickVideoAsync` silently failing on iOS, while working fine on Android The root cause is that `DismissViewController(animated:completion:)` accepts a completion callback precisely for this purpose — to run logic **after** the animation finishes — but the original code passed `null` and called the handler immediately after, creating a race condition. **Fix:** Moved all `CompletedHandler` invocations into the `completion` callback of `DismissViewController` across three call sites: - `UIImagePickerControllerDelegate.FinishedPickingMedia` - `UIImagePickerControllerDelegate.Canceled` - `PHPickerViewControllerDelegate.DidFinishPicking` ### Issues Fixed Fixes dotnet#21996 ### Testing Tested on a physical iOS device. - Opened image picker via `MediaPicker.PickPhotoAsync()` - After selecting an image, called `DisplayAlert` in the continuation - **Before fix:** alert did not appear after dismissing the picker - **After fix:** alert appears correctly after the picker is fully dismissed
…troller (#34250) ### Description of Change On iOS, `CompletedHandler` was being invoked **before** `DismissViewController` had finished animating. This means any code running in the handler — such as showing an alert, opening a modal, or triggering navigation — would fire while the picker view controller was still visible and attached to the view hierarchy. iOS UIKit requires the presenting view controller to be fully visible and attached before presenting any new UI (alerts, modals, sheets). If you attempt to present something while a dismiss animation is still in progress, UIKit silently drops the presentation or throws a warning, resulting in: - `DisplayAlert` / `DisplayActionSheet` not appearing after picking an image - Custom modal dialogs not showing up - Any `await`-based UI call after `PickPhotoAsync` / `PickVideoAsync` silently failing on iOS, while working fine on Android The root cause is that `DismissViewController(animated:completion:)` accepts a completion callback precisely for this purpose — to run logic **after** the animation finishes — but the original code passed `null` and called the handler immediately after, creating a race condition. **Fix:** Moved all `CompletedHandler` invocations into the `completion` callback of `DismissViewController` across three call sites: - `UIImagePickerControllerDelegate.FinishedPickingMedia` - `UIImagePickerControllerDelegate.Canceled` - `PHPickerViewControllerDelegate.DidFinishPicking` ### Issues Fixed Fixes #21996 ### Testing Tested on a physical iOS device. - Opened image picker via `MediaPicker.PickPhotoAsync()` - After selecting an image, called `DisplayAlert` in the continuation - **Before fix:** alert did not appear after dismissing the picker - **After fix:** alert appears correctly after the picker is fully dismissed
## What's Coming .NET MAUI inflight/candidate introduces significant improvements across all platforms with focus on quality, performance, and developer experience. This release includes 46 commits with various improvements, bug fixes, and enhancements. ## Button - [Android] Implemented material3 support for Button by @Dhivya-SF4094 in #33173 <details> <summary>🔧 Fixes</summary> - [Implement Material3 support for Button](#33172) </details> ## CollectionView - [Android] Fix RemainingItemsThresholdReachedCommand not firing when CollectionView has Header and Footer both defined by @SuthiYuvaraj in #29618 <details> <summary>🔧 Fixes</summary> - [Android : RemainingItemsThresholdReachedCommand not firing when CollectionVew has Header and Footer both defined](#29588) </details> - [iOS/MacCatalyst] Fix CollectionView ScrollTo for horizontal layouts by @Shalini-Ashokan in #33853 <details> <summary>🔧 Fixes</summary> - [[iOS/MacCatalyst] CollectionView ScrollTo does not work with horizontal Layout](#33852) </details> - [iOS & Mac] Fixed IndicatorView Size doesnt update dynamically by @SubhikshaSf4851 in #31129 <details> <summary>🔧 Fixes</summary> - [[iOS, Catalyst] IndicatorView.IndicatorSize does not update dynamically at runtime](#31064) </details> - [Android] Fix for CollectionView Scrolled event is triggered on the initial app load. by @BagavathiPerumal in #33558 <details> <summary>🔧 Fixes</summary> - [[Android] CollectionView Scrolled event is triggered on the initial app load.](#33333) </details> - [iOS, Android] Fix for CollectionView IsEnabled=false allows touch interactions by @praveenkumarkarunanithi in #31403 <details> <summary>🔧 Fixes</summary> - [More issues with CollectionView IsEnabled, InputTransparent, Opacity via Styles and code behind](#19771) </details> - [iOS] Fix VerticalOffset Update When Modifying CollectionView.ItemsSource While Scrolled by @devanathan-vaithiyanathan in #34153 <details> <summary>🔧 Fixes</summary> - [[iOS]VerticalOffset Not Reset to Zero After Clearing ItemSource in CollectionView](#26798) </details> ## DateTimePicker - [Android] Fix DatePicker MinimumDate/MaximumDate not updating dynamically by @HarishwaranVijayakumar in #33687 <details> <summary>🔧 Fixes</summary> - [[regression/8.0.3] [Android] DatePicker control minimum date issue](#19256) - [[Android] DatePicker does not update MinimumDate / MaximumDate in the Popup when set in the viewmodel after first opening](#33583) </details> ## Drawing - Android drawable perf by @albyrock87 in #31567 ## Editor - [Android] Implemented material3 support for Editor by @SyedAbdulAzeemSF4852 in #33478 <details> <summary>🔧 Fixes</summary> - [Implement Material3 Support for Editor](#33476) </details> ## Entry - [iOS, Mac] Fix for CursorPosition not updating when typing into Entry control by @SyedAbdulAzeemSF4852 in #30505 <details> <summary>🔧 Fixes</summary> - [Entry control CursorPosition does not update on TextChanged event [iOS Maui 8.0.7] ](#20911) - [CursorPosition not calculated correctly on behaviors events for iOS devices](#32483) </details> ## Flyoutpage - [Android, Windows] Fix for FlyoutPage toolbar button not updating on orientation change by @praveenkumarkarunanithi in #31962 <details> <summary>🔧 Fixes</summary> - [Flyout page in Android does not show flyout button (burger) consistently](#24468) </details> - Fix for First Item in CollectionView Overlaps in FlyoutPage.Flyout on iOS by @praveenkumarkarunanithi in #29265 <details> <summary>🔧 Fixes</summary> - [[iOS] CollectionView not rendering first item correctly in FlyoutPage.Flyout](#29170) </details> ## Image - [Android] Fix excessive memory usage for stream and resource-based image loading by @Shalini-Ashokan in #33590 <details> <summary>🔧 Fixes</summary> - [[Android] Unexpected high Bitmap.ByteCount when loading image via ImageSource.FromResource() or ImageSource.FromStream() in .NET MAUI](#33239) </details> - [Android] Fix for Resize method returns an image that has already been disposed by @SyedAbdulAzeemSF4852 in #29964 <details> <summary>🔧 Fixes</summary> - [In GraphicsView, the Resize method returns an image that has already been disposed](#29961) - [IIMage.Resize bugged behaviour](#31103) </details> ## Label - Fixed Label Span font property inheritance when applied via Style by @SubhikshaSf4851 in #34110 <details> <summary>🔧 Fixes</summary> - [`Span` does not inherit text styling from `Label` if that styling is applied using `Style` ](#21326) </details> - [Android] Implemented material3 support for Label by @SyedAbdulAzeemSF4852 in #33599 <details> <summary>🔧 Fixes</summary> - [Implement Material3 Support for Label](#33598) </details> ## Map - [Android] Fix Circle Stroke color is incorrectly updated as Fill color. by @NirmalKumarYuvaraj in #33643 <details> <summary>🔧 Fixes</summary> - [[Android] Circle Stroke color is incorrectly updated as Fill color.](#33642) </details> ## Mediapicker - [iOS] Fix: invoke MediaPicker completion handler after DismissViewController by @yuriikyry4enko in #34250 <details> <summary>🔧 Fixes</summary> - [[iOS] Media Picker UIImagePickerController closing issue](#21996) </details> ## Navigation - Fix ContentPage memory leak on Android when using NavigationPage modally (fixes #33918) by @brunck in #34117 <details> <summary>🔧 Fixes</summary> - [[Android] Modal TabbedPage whose tabs are NavigationPage(ContentPage) is retained after PopModalAsync()](#33918) </details> ## Picker - [Android] Implement material3 support for TimePicker by @HarishwaranVijayakumar in #33646 <details> <summary>🔧 Fixes</summary> - [Implement Material3 support for TimePicker](#33645) </details> - [Android] Implemented Material3 support for Picker by @SyedAbdulAzeemSF4852 in #33668 <details> <summary>🔧 Fixes</summary> - [Implement Material3 support for Picker](#33665) </details> ## RadioButton - [Android] Implemented material3 support for RadioButton by @SyedAbdulAzeemSF4852 in #33468 <details> <summary>🔧 Fixes</summary> - [Implement Material3 Support for RadioButton](#33467) </details> ## Setup - Clarify MA003 error message by @jeremy-visionaid in #34067 <details> <summary>🔧 Fixes</summary> - [MA003 false positive with 9.0.21](#26599) </details> ## Shell - [Android] Fix TabBar FlowDirection not updating dynamically by @SubhikshaSf4851 in #33091 <details> <summary>🔧 Fixes</summary> - [[Android, iOS] FlowDirection RTL is not updated dynamically on Shell TabBar](#32993) </details> - [Android] Fix page not disposed on Shell replace navigation by @Vignesh-SF3580 in #33426 <details> <summary>🔧 Fixes</summary> - [[Android] [Shell] replace navigation leaks current page](#25134) </details> - [Android] Fixed Shell flyout does not disable scrolling when FlyoutVerticalScrollMode is set to Disabled by @NanthiniMahalingam in #32734 <details> <summary>🔧 Fixes</summary> - [[Android] Shell.FlyoutVerticalScrollMode="Disabled" does not disable scrolling](#32477) </details> ## Single Project - Fix: Throw a clear error when an SVG lacks dimensions instead of a NullReferenceException by @Shalini-Ashokan in #33194 <details> <summary>🔧 Fixes</summary> - [MAUI Fails To Convert Valid SVG Files Into PNG Files (Object reference not set to an instance of an object)](#32460) </details> ## SwipeView - [iOS] Fix SwipeView stays open on iOS after updating content by @devanathan-vaithiyanathan in #31248 <details> <summary>🔧 Fixes</summary> - [[iOS] - Swipeview with collectionview issue](#19541) </details> ## TabbedPage - [Windows] Fixed IsEnabled Property not works on Tabs by @NirmalKumarYuvaraj in #26728 <details> <summary>🔧 Fixes</summary> - [ShellContent IsEnabledProperty does not work](#5161) - [[Windows] Shell Tab IsEnabled Not Working](#32996) </details> - [Android] Fix NavigationBar overlapping StatusBar when NavigationBar visibility changes by @Vignesh-SF3580 in #33359 <details> <summary>🔧 Fixes</summary> - [[Android] NavigationBar overlaps with StatusBar when mixing HasNavigationBar=true/false in TabbedPage on Android 15 (API 35)](#33340) </details> ## Templates - Fix for unable to open task using keyboard navigation on windows platform by @SuthiYuvaraj in #33647 <details> <summary>🔧 Fixes</summary> - [Unable to open task using keyboard: A11y_.NET maui_User can get all the insights of Dashboard_Keyboard](#30787) </details> ## TitleView - Fix for NavigationPage.TitleView does not expand with host window in iPadOS 26+ by @SuthiYuvaraj in #33088 ## Toolbar - [iOS] Fix toolbar items ignoring BarTextColor on iOS/MacCatalyst 26+ by @Shalini-Ashokan in #34036 <details> <summary>🔧 Fixes</summary> - [[iOS 26] ToolbarItem color with custom BarTextColor not working](#33970) </details> - [Android] Fix for ToolbarItem retaining the icon from the previous page on Android when using NavigationPage. by @BagavathiPerumal in #32311 <details> <summary>🔧 Fixes</summary> - [Toolbaritem keeps the icon of the previous page on Android, using NavigationPage (not shell)](#31727) </details> ## WebView - [Android] Fix WebView in a grid expands beyond it's cell by @devanathan-vaithiyanathan in #32145 <details> <summary>🔧 Fixes</summary> - [Android - WebView in a grid expands beyond it's cell](#32030) </details> ## Xaml - ContentPresenter: Propagate binding context to children with explicit TemplateBinding by @HarishwaranVijayakumar in #30880 <details> <summary>🔧 Fixes</summary> - [Binding context in ContentPresenter](#23797) </details> <details> <summary>🔧 Infrastructure (1)</summary> - [Revert] ContentPresenter: Propagate binding context to children with explicit TemplateBinding by @Ahamed-Ali in #34332 </details> <details> <summary>🧪 Testing (6)</summary> - [Testing] Feature Matrix UITest Cases for Shell Flyout Page by @NafeelaNazhir in #32525 - [Testing] Feature Matrix UITest Cases for Brushes by @LogishaSelvarajSF4525 in #31833 - [Testing] Feature Matrix UITest Cases for BindableLayout by @LogishaSelvarajSF4525 in #33108 - [Android] Add UI tests for Material 3 CheckBox by @HarishwaranVijayakumar in #34126 <details> <summary>🔧 Fixes</summary> - [[Android] Add UI tests for Material 3 CheckBox](#34125) </details> - [Testing] Feature Matrix UITest Cases for Shell Tabbed Page by @NafeelaNazhir in #33159 - [Testing] Fixed Test case failure in PR 34294 - [03/2/2026] Candidate - 1 by @TamilarasanSF4853 in #34334 </details> <details> <summary>📦 Other (2)</summary> - Bumps Syncfusion.Maui.Toolkit dependency to version 1.0.9 by @PaulAndersonS in #34178 - Fix crash when closing Windows based app when using TitleBar by @MFinkBK in #34032 <details> <summary>🔧 Fixes</summary> - [Unhandled exception "Value does not fall within the expected range" when closing Windows app](#32194) </details> </details> **Full Changelog**: main...inflight/candidate
Description of Change
On iOS,
CompletedHandlerwas being invoked beforeDismissViewControllerhad finished animating. This means any code running in the handler — such as
showing an alert, opening a modal, or triggering navigation — would fire while
the picker view controller was still visible and attached to the view hierarchy.
iOS UIKit requires the presenting view controller to be fully visible and
attached before presenting any new UI (alerts, modals, sheets). If you attempt
to present something while a dismiss animation is still in progress, UIKit
silently drops the presentation or throws a warning, resulting in:
DisplayAlert/DisplayActionSheetnot appearing after picking an imageawait-based UI call afterPickPhotoAsync/PickVideoAsyncsilently failing on iOS, while working fine on AndroidThe root cause is that
DismissViewController(animated:completion:)accepts acompletion callback precisely for this purpose — to run logic after the
animation finishes — but the original code passed
nulland called the handlerimmediately after, creating a race condition.
Fix: Moved all
CompletedHandlerinvocations into thecompletioncallbackof
DismissViewControlleracross three call sites:UIImagePickerControllerDelegate.FinishedPickingMediaUIImagePickerControllerDelegate.CanceledPHPickerViewControllerDelegate.DidFinishPickingIssues Fixed
Fixes #21996
Testing
Tested on a physical iOS device.
MediaPicker.PickPhotoAsync()DisplayAlertin the continuation