Fix Changing Location on a Pin does nothing#30201
Fix Changing Location on a Pin does nothing#30201kubaflo merged 10 commits intodotnet:inflight/currentfrom
Conversation
jsuarezruiz
left a comment
There was a problem hiding this comment.
Could you include the sample from the issue in the Gallery? https://github.com/dotnet/maui/tree/main/src/Controls/samples/Controls.Sample/Pages/Controls/MapsGalleries
@jsuarezruiz , i have modified the gallery and introduced a move pin button to update the pin. |
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
| _randomLocations[_locationRandomSeed.Next(_randomLocations.Length)]; | ||
|
|
||
| void MoveMapTo(Position location) => | ||
| pinsMap.MoveToRegion(MapSpan.FromCenterAndRadius(location, Distance.FromKilometers(5))); |
There was a problem hiding this comment.
Could be nice to create a constant:
const double DefaultMapRadiusKm = 5.0;
There was a problem hiding this comment.
@jsuarezruiz . Done . Please let me know if you have concerns.
| // to avoid potential memory leaks (the Marker is owned by the Google Maps view) | ||
| WeakReference<Marker>? _markerWeakReference; | ||
|
|
||
| internal Marker? Marker |
There was a problem hiding this comment.
Add a DisconnectHandler override to properly clean up the weak reference when the handler is disconnected.
There was a problem hiding this comment.
@jsuarezruiz , Added DisconnectHandler. Please let me know if you have any concerns.
7813aa0 to
8a04fa5
Compare
There was a problem hiding this comment.
Pull Request Overview
This PR fixes a bug where changing the Location property on a Microsoft.Maui.Controls.Maps.Pin does not update the pin's position on the map in Android. The issue was that only the MarkerOptions object was being updated when properties changed, but the actual Marker already added to the map was not being updated.
Key Changes
- Added marker reference tracking in MapPinHandler to maintain connection between pins and their associated markers
- Updated property mappers to modify both MarkerOptions and the actual Marker when pin properties change
- Enhanced the MapPinsGallery sample with functionality to test pin movement
Reviewed Changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
MapPinHandler.Android.cs |
Added WeakReference-based marker tracking and updated property mappers to modify both MarkerOptions and actual Marker |
MapHandler.Android.cs |
Modified AddPins method to store marker reference in MapPinHandler for future property updates |
PublicAPI.Unshipped.txt |
Added new public API entry for the DisconnectHandler override |
MapPinsGallery.xaml |
Added "Move Pin" button to test pin location changes |
MapPinsGallery.xaml.cs |
Implemented pin movement functionality and improved random location handling |
|
|
|
🚀 Dogfood this PR with:
curl -fsSL https://github.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 30201Or
iex "& { $(irm https://github.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 30201" |
|
@kubaflo , Addressed AI summary concerns |
|
@kubaflo , Fix is applied in Map control . For Android platform, we need an API key to render map. so skipped writing test for this PR. I have enabled a button to move the pin in the control gallery sample. You can verify there. Please let me know if you have any concerns. |
🚦 Gate — Test Before and After Fix
🚦 Gate Session —
|
🤖 AI Summary
📊 Review Session —
|
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #30201 | Subscribe INotifyPropertyChanged.PropertyChanged in MapHandler.AddPins(); look up live Marker via O(n) _markers list scan by string MarkerId; update marker.Position/Title/Snippet directly |
MapHandler.Android.cs, MapPinHandler.Android.cs (style-only), PublicAPI.Unshipped.txt (cosmetic), 2 sample files |
Updated fix; MarkerId stays as string; GetPinForMarker() unchanged |
🔧 Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix (claude-opus-4.6) | Dictionary<IMapPin, Marker> keyed by pin object reference; same PropertyChanged subscription; O(1) lookup |
1 file | Eliminates string MarkerId indirection; clean O(1) lookup | |
| 2 | try-fix (claude-sonnet-4.6) | Action<string>? LiveMarkerUpdate closure on MapPinHandler; MapHandler captures live Marker in closure after AddMarker(); no INPC subscription |
2 files | Zero subscription overhead; update logic stays in MapHandler; most decoupled approach | |
| 3 | try-fix (gpt-5.3-codex) | MapPinMarkerId wrapper object stored in IMapPin.MarkerId; mapper directly updates live Marker via cast |
❌ FAIL (build env TFM issue — --no-restore caused MSB3644; code logic sound) |
2 files | Requires correct build command (-f net10.0-android36.0, no --no-restore) |
| 4 | try-fix (gpt-5.4) | Remove-and-re-add Marker: MapHandler.RefreshPinMarker() removes old marker and adds fresh one from MarkerOptions; called from MapPinHandler |
✅ BUILD PASS (build verified; no device runtime test) | 2 files | Visual flash on update; correct fix but worse UX; avoids all INPC subscriptions |
| PR | PR #30201 | INotifyPropertyChanged.PropertyChanged in MapHandler.AddPins(); O(n) scan of _markers list by string MarkerId; updates marker.Position/Title/Snippet |
MapHandler.Android.cs, MapPinHandler.Android.cs (style), PublicAPI.Unshipped.txt (cosmetic), 2 sample files |
Standard MAUI INPC pattern; in-place update (no visual flash); handles Location/Label/Address |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| claude-opus-4.6 | 2 | Yes | Marker.Tag-based identity: store IMapPin as marker.Tag; iterate markers matching Tag for update — functionally same axis as Dict approaches (still O(n) scan or requires dict); not run as separate attempt |
| gpt-5.3-codex | 2 | Yes (but regressive) | Store live Marker object in IMapPin.MarkerId — this is the old PR approach known to break GetPinForMarker() string comparison; rejected |
Exhausted: Yes — all architectural axes covered: INPC subscription (PR, Attempt 1), closure capture (Attempt 2), wrapper/casting (Attempt 3), remove-and-recreate (Attempt 4). Cross-poll Attempt 2 variants (Tag, Marker-in-MarkerId) are regressions to previously-tried or inferior approaches.
Selected Fix: PR's fix — Uses standard MAUI INPC pattern; in-place marker.Position update (no visual flash); correctly handles Location, Label, and Address changes; MarkerId stays as string so GetPinForMarker() is untouched; most pattern-consistent with rest of MapHandler codebase.
📋 Report — Final Recommendation
⚠️ Final Recommendation: REQUEST CHANGES
Phase Status
| Phase | Status | Notes |
|---|---|---|
| Pre-Flight | ✅ COMPLETE | Issue #12916, Android-only, PR significantly updated; prior full review imported |
| Gate | No automated tests detected in PR | |
| Try-Fix | ✅ COMPLETE | 4 attempts; 1 build-verified alternative (remove-and-re-add); 2 blocked (no device); 1 env failure; PR's fix selected |
| Report | ✅ COMPLETE |
Summary
PR #30201 correctly fixes the long-standing Android regression (#12916) where Pin.Location changes had no visual effect. The root cause is properly identified and the implementation is sound. However, there are two remaining blocking concerns before merge:
-
DisconnectPins()callspin?.Handler?.DisconnectHandler()on pin handlers — This manually manages child handler lifecycle from the parentMapHandler. It is called from bothDisconnectHandler(teardown) and theMapPinsmapper (full pins refresh). TheMapPinsmapper also calls it during a pins collection refresh, meaning all pin handlers are disconnected and their handlers disconnected on every full refresh. This unusual pattern could cause issues if pin handlers are expected to be managed exclusively by the MAUI framework. A maintainer should explicitly confirm this is the intended lifecycle. -
Merge conflict — The PR has an unresolved conflict with
main(detected 2026-03-21, still unresolved). Must be resolved before merge. -
No automated tests — Author explains Google Maps API key is required. A gallery "Move Pin" button was added as manual validation. The gate was skipped as a result.
-
PublicAPI.Unshipped.txttrailing newline removal — Cosmetic-only; no functional impact but adds noise to the diff. The file should have a trailing newline per file conventions.
Root Cause
MapPinHandler.MapLocation calls handler.PlatformView.SetPosition(...) on the MarkerOptions template object. Once Map.AddMarker(markerOptions) returns a live Marker, any subsequent changes to the MarkerOptions instance have no effect on the rendered pin. The live Marker must be updated directly. The fix correctly adds a PropertyChanged listener in MapHandler.AddPins() to intercept pin property changes and update the corresponding live Marker.
Fix Quality
The PR's INotifyPropertyChanged.PropertyChanged approach is the best-fit solution for this codebase:
- Try-Fix confirmed 7+ alternative approaches; none improves on the PR while staying consistent with MAUI patterns.
- The closest alternative (Attempt 2: closure-based LiveMarkerUpdate) avoids event subscriptions but adds a stateful delegate to
MapPinHandlerthat couples it toMapHandler— rejected by earlier inline review comments. - The next best (Attempt 4: remove-and-re-add) builds correctly but causes visual flash on location update — inferior UX.
MarkerIdcorrectly remains astring;GetPinForMarker()is unchanged and correct.
Selected Fix: PR — most pattern-consistent, in-place update, handles Location/Label/Address.
Required Before Merge
- Resolve merge conflict with
main - Review or justify
pin?.Handler?.DisconnectHandler()call inDisconnectPins()— confirm this is intended lifecycle management and not an unintended double-disconnect - (Optional) Restore trailing newline in
PublicAPI.Unshipped.txt - (Optional) Add a comment in
DisconnectPins()explaining why child handler disconnect is explicit here
|
@kubaflo , Addressed AI summary concern. please let me know if you have any concerns. |
Code Review — PR #30201Independent AssessmentWhat this changes: On Android, subscribes to Inferred motivation: Changing Reconciliation with PR NarrativeAuthor claims: Changing Location on a Pin does nothing on Android. Root cause is that only MarkerOptions was being updated, not the live Marker. Agreement: My analysis matches exactly. The Findings
|
<!-- 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! ### Issue details Changing the Location property on a Microsoft.Maui.Controls.Maps.Pin does not change the location of the Pin on the map. ### Root cause `MapPinHandler.Android.cs` was only updating the `MarkerOptions` object when the Location property changed The actual `Marker` object already added to the map was not being updated, causing the pin to stay in its original location <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Description of change * **Improved marker association logic**: Updated the `AddPins` method in `MapHandler` to store marker references in the `MapPinHandler` for future property updates, ensuring tighter integration between pins and markers. Validated the behaviour in the following platforms - [x] Android - [ ] Windows - [ ] iOS - [ ] Mac ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #12916 <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. --> ### Output | Before| After| |--|--| | <video src="https://github.com/user-attachments/assets/83bedab7-846b-41c1-872e-b6e0d0cd81a4"> | <video src="https://github.com/user-attachments/assets/fd86fd38-6619-4cf9-999a-de9d05b21e17"> | --------- Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
<!-- 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! ### Issue details Changing the Location property on a Microsoft.Maui.Controls.Maps.Pin does not change the location of the Pin on the map. ### Root cause `MapPinHandler.Android.cs` was only updating the `MarkerOptions` object when the Location property changed The actual `Marker` object already added to the map was not being updated, causing the pin to stay in its original location <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Description of change * **Improved marker association logic**: Updated the `AddPins` method in `MapHandler` to store marker references in the `MapPinHandler` for future property updates, ensuring tighter integration between pins and markers. Validated the behaviour in the following platforms - [x] Android - [ ] Windows - [ ] iOS - [ ] Mac ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes dotnet#12916 <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. --> ### Output | Before| After| |--|--| | <video src="https://github.com/user-attachments/assets/83bedab7-846b-41c1-872e-b6e0d0cd81a4"> | <video src="https://github.com/user-attachments/assets/fd86fd38-6619-4cf9-999a-de9d05b21e17"> | --------- Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
<!-- 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! ### Issue details Changing the Location property on a Microsoft.Maui.Controls.Maps.Pin does not change the location of the Pin on the map. ### Root cause `MapPinHandler.Android.cs` was only updating the `MarkerOptions` object when the Location property changed The actual `Marker` object already added to the map was not being updated, causing the pin to stay in its original location <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Description of change * **Improved marker association logic**: Updated the `AddPins` method in `MapHandler` to store marker references in the `MapPinHandler` for future property updates, ensuring tighter integration between pins and markers. Validated the behaviour in the following platforms - [x] Android - [ ] Windows - [ ] iOS - [ ] Mac ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #12916 <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. --> ### Output | Before| After| |--|--| | <video src="https://github.com/user-attachments/assets/83bedab7-846b-41c1-872e-b6e0d0cd81a4"> | <video src="https://github.com/user-attachments/assets/fd86fd38-6619-4cf9-999a-de9d05b21e17"> | --------- Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
<!-- 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! ### Issue details Changing the Location property on a Microsoft.Maui.Controls.Maps.Pin does not change the location of the Pin on the map. ### Root cause `MapPinHandler.Android.cs` was only updating the `MarkerOptions` object when the Location property changed The actual `Marker` object already added to the map was not being updated, causing the pin to stay in its original location <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Description of change * **Improved marker association logic**: Updated the `AddPins` method in `MapHandler` to store marker references in the `MapPinHandler` for future property updates, ensuring tighter integration between pins and markers. Validated the behaviour in the following platforms - [x] Android - [ ] Windows - [ ] iOS - [ ] Mac ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #12916 <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. --> ### Output | Before| After| |--|--| | <video src="https://github.com/user-attachments/assets/83bedab7-846b-41c1-872e-b6e0d0cd81a4"> | <video src="https://github.com/user-attachments/assets/fd86fd38-6619-4cf9-999a-de9d05b21e17"> | --------- Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
<!-- 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! ### Issue details Changing the Location property on a Microsoft.Maui.Controls.Maps.Pin does not change the location of the Pin on the map. ### Root cause `MapPinHandler.Android.cs` was only updating the `MarkerOptions` object when the Location property changed The actual `Marker` object already added to the map was not being updated, causing the pin to stay in its original location <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Description of change * **Improved marker association logic**: Updated the `AddPins` method in `MapHandler` to store marker references in the `MapPinHandler` for future property updates, ensuring tighter integration between pins and markers. Validated the behaviour in the following platforms - [x] Android - [ ] Windows - [ ] iOS - [ ] Mac ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #12916 <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. --> ### Output | Before| After| |--|--| | <video src="https://github.com/user-attachments/assets/83bedab7-846b-41c1-872e-b6e0d0cd81a4"> | <video src="https://github.com/user-attachments/assets/fd86fd38-6619-4cf9-999a-de9d05b21e17"> | --------- Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
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 from this PR and let us know in a comment if this change resolves your issue. Thank you!
Issue details
Changing the Location property on a Microsoft.Maui.Controls.Maps.Pin does not change the location of the Pin on the map.
Root cause
MapPinHandler.Android.cswas only updating theMarkerOptionsobject when the Location property changedThe actual
Markerobject already added to the map was not being updated, causing the pin to stay in its original locationDescription of change
AddPinsmethod inMapHandlerto store marker references in theMapPinHandlerfor future property updates, ensuring tighter integration between pins and markers.Validated the behaviour in the following platforms
Issues Fixed
Fixes #12916
Output
Before.mov
After.mov