VladislavAntonyuk/MauiSamples

Custom pins are not shown anymore on iOS after maps pin itemsource changes

VToegel opened this issue · 11 comments

Dear Vladislav,

first of all: Thank you for your great examples and blog posts.
Second: I have an interesting problem with custom map pins only on iOS. When the Map view and viewmodel is loaded the first time, everything works fine, but after i change the itemsource for the pins (e.g. sort the collection - > Venues = new ObservableCollection(CachedVenues.OrderBy(x => x.Name));) the pins are gone, together with the own position marker on the map view. The fail is quiet (no exception whatsoever).

I tried to troubleshoot for 2 days now with no avail. I suspect the problem in the addAnnotation method together with the GetViewForAnnotations method within MapExtensions

Within the GetViewForAnnotations the condition

if (annotation is CustomAnnotation customAnnotation) {...}

triggers the first time round but not after the itemsource is changed, because then only MKPointAnnotation types are available.

To confirm: the code works as intended as long as the itemsource is not changed. As soon as the itemsource is sorted and the change notified all markers together with the own position marker are gone from the map.

I would be really greatful if you can give me a hint to point into the right direction if you got any idea.

Thanks and Stay Safe,

Rgds Vinc

<maps:Map x:Name="mapIOS" AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All" IsShowingUser="True" IsTrafficEnabled="True" ItemsSource="{Binding DataService.Venues, Mode=OneWay}"> <maps:Map.ItemTemplate> <DataTemplate> <pin:CustomPin x:DataType="models:Venue" Address="{Binding Address}" ImageSource="locationpin.png" InfoWindowClicked="Pin_InfoWindowClicked" Label="{Binding Name}" Map="{x:Reference mapIOS}" MarkerClicked="Pin_MarkerClicked"> <pin:CustomPin.Location> <MultiBinding Converter="{StaticResource LatLonToLocationConverter}"> <Binding Path="Latitude" /> <Binding Path="Longitude" /> </MultiBinding> </pin:CustomPin.Location> </pin:CustomPin> </DataTemplate> </maps:Map.ItemTemplate> </maps:Map>

hey @VToegel. could you please attach a small repro? it will be much easier for me to reproduce the issue. feel free to update current MauiSamples.MauiMaps sample. Thank you.
Most likely some MAUI events may clean up pins and rerender them.

Hi @VladislavAntonyuk ,

of course. Please find attached a modified .zip of your repository.

I added a very simplified pin location service with a refresh (sorting), a MainPageViewModel as well as dependency injection for service, view and viewmodel and bound everything to MyMap2 (the other map is unmodified). In addition i added a Refreshbutton and modified the MapExtension AddAnnotation method slightly to be more universal for input types.

As you can see in the attached screenshots the pins are shown after App Init (look in the area of munich) but are gone after the itemsource is sorted by using refresh.
In addition i observed that "ShowUserLocation = true" is NOT working with custom pins on iOS.
On Android i did not observe any problem.
I tried today again to find a root cause but i am still scratchin my head.. ;-)

Thanks for your fast feedback,

Rgds Vinc

BeforeRefresh

AfterRefresh

MauiMaps.zip

I reproduced the issue.
this code from .NET MAUI reset the custom annotation
image

As a result, all annotations are converted to MKPointAnnotation.
image

most likely we need a custom handler for pins

Fixed. I will update article according to the changes

@VladislavAntonyuk 👍
Thank you very much, your responsiveness was a really great! Will implement your solution this evening.
Coffee is on the way ;-)

Thank you, the update works, but.... the "ShowUserLocation" is still missing.
Do you perhaps have an idea?

Take a look at the method GetViewForAnnotation. It is responsible for rendering views on maps. There should be a specific annotation type for the user. I may take a look later this week.

Got it,

just change one line within GetViewForAnnotation.

Change
var result = annotationView ?? new MKAnnotationView(annotation, null);
to
var result = annotationView ?? new MKUserLocationView(annotation, null);

and all is good!

Reds Vinc

But now the default pin (not custom pin) is rendered as UserLocationView

True enough,

revised to:

private static MKAnnotationView GetViewForAnnotations(MKMapView mapView, IMKAnnotation annotation)
   {
       MKAnnotationView? annotationView = null;
       if (annotation is CustomAnnotation customAnnotation)
       {
           annotationView = mapView.DequeueReusableAnnotation(customAnnotation.Identifier.ToString()) ??
                            new MKAnnotationView(annotation, customAnnotation.Identifier.ToString());
           annotationView.Image = customAnnotation.Image;
           annotationView.CanShowCallout = true;
       }
       else if (annotation is MKPointAnnotation mkAnnotation)
       {
           annotationView = mapView.DequeueReusableAnnotation("defaultPin") ??
                            new MKMarkerAnnotationView(annotation, "defaultPin");
           annotationView.CanShowCallout = true;
       }
       else
       {
           annotationView = new MKUserLocationView(annotation, null);
        }
       
       var result = annotationView ?? new MKAnnotationView(annotation, null);
       AttachGestureToPin(result, annotation);
       return result;
  }

Now standard pin, custom pin and UserLocation work.

Rgds

Vinc
p.s. sry, first time working with MapKit, I am learning a lot ;-)

to be honest, me too ;-) This code should work. Thank you!