maui icon indicating copy to clipboard operation
maui copied to clipboard

Disconnecting Map Handler causes Map to crash on second page entrance and moving to region.

Open awasilik opened this issue 2 years ago • 2 comments

Description

In my company application we have a map control with logic that moves Map to specific region when data loads. We have a custom Handler for which we call DisconnectHandler.

After second time page is opened and region is changed there is a crash with

System.InvalidOperationException: VirtualView cannot be null here

I've prepared a Sandbox application that reproduces the issue easily: https://github.com/awasilik/MauiMapBug

Steps to Reproduce

  1. Open Sandbox application
  2. Click OpenMap button
  3. Let the region change and press "Go back" button
  4. Click OpenMap button again

Crash occurs

Link to public reproduction project repository

https://github.com/awasilik/MauiMapBug

Version with bug

8.0.6 SR1

Is this a regression from previous behavior?

No, this is something new

Last version that worked well

Unknown/Other

Affected platforms

iOS

Affected platform versions

iPhone 8 with iOS 15.6 (other iPhones have the same issue)

Did you find any workaround?

Commenting out base.DisconnectHandler(mapView);

in custom map handler.

Relevant log output

System.InvalidOperationException: VirtualView cannot be null here
   at Microsoft.Maui.Handlers.ViewHandler`2[[Microsoft.Maui.Maps.IMap, Microsoft.Maui.Maps, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Maps.Platform.MauiMKMapView, Microsoft.Maui.Maps, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].get_VirtualView()
   at Microsoft.Maui.Maps.Handlers.MapHandler.Microsoft.Maui.Maps.Handlers.IMapHandler.get_VirtualView()
   at Microsoft.Maui.Maps.Platform.MauiMKMapView.MkMapViewOnRegionChanged(Object sender, MKMapViewChangeEventArgs e)
   at MapKit.MKMapView._MKMapViewDelegate.RegionChanged(MKMapView mapView, Boolean animated) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/build/dotnet/ios/generated-sources/MapKit/MKMapView.g.cs:line 1956
   at MapKit.MKMapView.SetRegion(MKCoordinateRegion region, Boolean animated) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/build/dotnet/ios/generated-sources/MapKit/MKMapView.g.cs:line 759
   at Microsoft.Maui.Maps.Handlers.MapHandler.MoveToRegion(MapSpan mapSpan, Boolean animated)
   at Microsoft.Maui.Maps.Handlers.MapHandler.MapMoveToRegion(IMapHandler handler, IMap map, Object arg)
   at Microsoft.Maui.CommandMapper`2.<>c__DisplayClass6_0[[Microsoft.Maui.Maps.IMap, Microsoft.Maui.Maps, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Maps.Handlers.IMapHandler, Microsoft.Maui.Maps, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].<Add>b__0(IElementHandler h, IElement v, Object o)
   at Microsoft.Maui.CommandMapper.InvokeCore(String key, IElementHandler viewHandler, IElement virtualView, Object args)
   at Microsoft.Maui.CommandMapper.Invoke(IElementHandler viewHandler, IElement virtualView, String property, Object args)
   at Microsoft.Maui.Handlers.ElementHandler.Invoke(String command, Object args)
   at Microsoft.Maui.Controls.Maps.Map.MoveToRegion(MapSpan mapSpan)
   at MapBugApp.MapPage.<MoveMap>b__1_0() in /Users/ADWA/Desktop/MapBugApp/MauiMapBug/MapBugApp/MapPage.xaml.cs:line 24
   at Foundation.NSAsyncActionDispatcher.Apply() in /Users/builder/azdo/_work/1/s/xamarin-macios/src/Foundation/NSAction.cs:line 150
   at UIKit.UIApplication.UIApplicationMain(Int32 argc, String[] argv, IntPtr principalClassName, IntPtr delegateClassName) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/UIKit/UIApplication.cs:line 58
   at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/UIKit/UIApplication.cs:line 94
   at MapBugApp.Program.Main(String[] args) in /Users/ADWA/Desktop/MapBugApp/MauiMapBug/MapBugApp/Platforms/iOS/Program.cs:line 13
2024-02-15 15:40:52.268 MapBugApp[99574:28420853] Unhandled managed exception: VirtualView cannot be null here (System.InvalidOperationException)
   at Microsoft.Maui.Handlers.ViewHandler`2[[Microsoft.Maui.Maps.IMap, Microsoft.Maui.Maps, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Maps.Platform.MauiMKMapView, Microsoft.Maui.Maps, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].get_VirtualView()
   at Microsoft.Maui.Maps.Handlers.MapHandler.Microsoft.Maui.Maps.Handlers.IMapHandler.get_VirtualView()
   at Microsoft.Maui.Maps.Platform.MauiMKMapView.MkMapViewOnRegionChanged(Object sender, MKMapViewChangeEventArgs e)
   at MapKit.MKMapView._MKMapViewDelegate.RegionChanged(MKMapView mapView, Boolean animated) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/build/dotnet/ios/generated-sources/MapKit/MKMapView.g.cs:line 1956
   at MapKit.MKMapView.SetRegion(MKCoordinateRegion region, Boolean animated) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/build/dotnet/ios/generated-sources/MapKit/MKMapView.g.cs:line 759
   at Microsoft.Maui.Maps.Handlers.MapHandler.MoveToRegion(MapSpan mapSpan, Boolean animated)
   at Microsoft.Maui.Maps.Handlers.MapHandler.MapMoveToRegion(IMapHandler handler, IMap map, Object arg)
   at Microsoft.Maui.CommandMapper`2.<>c__DisplayClass6_0[[Microsoft.Maui.Maps.IMap, Microsoft.Maui.Maps, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Maps.Handlers.IMapHandler, Microsoft.Maui.Maps, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].<Add>b__0(IElementHandler h, IElement v, Object o)
   at Microsoft.Maui.CommandMapper.InvokeCore(String key, IElementHandler viewHandler, IElement virtualView, Object args)
   at Microsoft.Maui.CommandMapper.Invoke(IElementHandler viewHandler, IElement virtualView, String property, Object args)
   at Microsoft.Maui.Handlers.ElementHandler.Invoke(String command, Object args)
   at Microsoft.Maui.Controls.Maps.Map.MoveToRegion(MapSpan mapSpan)
   at MapBugApp.MapPage.<MoveMap>b__1_0() in /Users/ADWA/Desktop/MapBugApp/MauiMapBug/MapBugApp/MapPage.xaml.cs:line 24
   at Foundation.NSAsyncActionDispatcher.Apply() in /Users/builder/azdo/_work/1/s/xamarin-macios/src/Foundation/NSAction.cs:line 150
   at UIKit.UIApplication.UIApplicationMain(Int32 argc, String[] argv, IntPtr principalClassName, IntPtr delegateClassName) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/UIKit/UIApplication.cs:line 58
   at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/UIKit/UIApplication.cs:line 94
   at MapBugApp.Program.Main(String[] args) in /Users/ADWA/Desktop/MapBugApp/MauiMapBug/MapBugApp/Platforms/iOS/Program.cs:line 13

=================================================================
	Native Crash Reporting
=================================================================
Got a SIGABRT while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.
=================================================================

=================================================================
	Native stacktrace:
=================================================================
	0x10487e5b0 - /private/var/containers/Bundle/Application/7000E81D-4B95-4035-9FA5-AC7499DC165B/MapBugApp.app/MapBugApp : AppleCryptoNative_X509ImportCollection
	0x10486949c - /private/var/containers/Bundle/Application/7000E81D-4B95-4035-9FA5-AC7499DC165B/MapBugApp.app/MapBugApp : AppleCryptoNative_X509ImportCollection
	0x1049b7a30 - /private/var/containers/Bundle/Application/7000E81D-4B95-4035-9FA5-AC7499DC165B/MapBugApp.app/MapBugApp : AppleCryptoNative_X509ImportCollection
	0x10487dda0 - /private/var/containers/Bundle/Application/7000E81D-4B95-4035-9FA5-AC7499DC165B/MapBugApp.app/MapBugApp : AppleCryptoNative_X509ImportCollection
	0x1dc05cd48 - /usr/lib/system/libsystem_platform.dylib : <redacted>
	0x1dc074854 - /usr/lib/system/libsystem_pthread.dylib : pthread_kill
	0x18b4056ac - /usr/lib/system/libsystem_c.dylib : abort
	0x1045562c8 - /private/var/containers/Bundle/Application/7000E81D-4B95-4035-9FA5-AC7499DC165B/MapBugApp.app/MapBugApp : xamarin_find_protocol_wrapper_type
	0x1047b4264 - /private/var/containers/Bundle/Application/7000E81D-4B95-4035-9FA5-AC7499DC165B/MapBugApp.app/MapBugApp : AppleCryptoNative_X509ImportCollection
	0x104853fbc - /private/var/containers/Bundle/Application/7000E81D-4B95-4035-9FA5-AC7499DC165B/MapBugApp.app/MapBugApp : AppleCryptoNative_X509ImportCollection
	0x104568fb8 - /private/var/containers/Bundle/Application/7000E81D-4B95-4035-9FA5-AC7499DC165B/MapBugApp.app/MapBugApp : xamarin_get_original_working_directory_path
	0x1048bc4f8 - /private/var/containers/Bundle/Application/7000E81D-4B95-4035-9FA5-AC7499DC165B/MapBugApp.app/MapBugApp : AppleCryptoNative_X509ImportCollection
	0x104f984d0 - Unknown

=================================================================
	Basic Fault Address Reporting
=================================================================
Memory around native instruction pointer (0x1bb5e6bbc):0x1bb5e6bac  c0 03 5f d6 c0 03 5f d6 10 29 80 d2 01 10 00 d4  .._..._..)......
0x1bb5e6bbc  e3 00 00 54 fd 7b bf a9 fd 03 00 91 91 ee ff 97  ...T.{..........
0x1bb5e6bcc  bf 03 00 91 fd 7b c1 a8 c0 03 5f d6 c0 03 5f d6  .....{...._..._.
0x1bb5e6bdc  fd 7b bf a9 fd 03 00 91 50 00 80 d2 01 10 00 d4  .{......P.......

=================================================================
	Managed Stacktrace:
=================================================================
=================================================================

awasilik avatar Feb 15 '24 14:02 awasilik

We've added this issue to our backlog, and we will work to address it as time and resources allow. If you have any additional information or questions about this issue, please leave a comment. For additional info about issue management, please read our Triage Process.

ghost avatar Feb 15 '24 19:02 ghost

I am also experiencing this issue. In my case I'm seeing the error when clearing and adding MapElements to my map on the second map page load. Thanks to @awasilik for the workaround of commenting out DisconnectHandler().

timdog avatar May 24 '24 14:05 timdog

The problem is the handler constructor and the use of a MapPool.

		protected override MauiMKMapView CreatePlatformView()
		{
			return MapPool.Get() ?? new MauiMKMapView(this);
		}

```		
it will reuse the MapView from the pool, but it was constructed with a previous handler that was disposed (virtual view will be null).
a work around I found is to overload the DisconnectHandler to prevent the call to MapPool.Add(platformView) in the base class.

I think a good way to fix this problem is to allow the handler to be set outside of the constructor, and we can just set it after we get the map from the pool.

Hobitus avatar Jun 20 '24 13:06 Hobitus

This is still an issue with .NET 9. With .NET 9, the disconnect handler is called automatically upon view disposal, witch requires revisiting all view using the control to opt-out from automatic disconnect.

kaniosm avatar Nov 17 '24 15:11 kaniosm

I agree this is still an issue - any work around as it makes map unusable - I have same use case as timdog- it blows up on adding MapElements

Does anyone have an example of overriding the disconnect handler?

michaelonz avatar Nov 18 '24 05:11 michaelonz

Hi @michaelonz ,

Simply override the DisconnectHandler in you custom handler as shown below: In my case, I'm disconnecting a few event handlers, and commented out the call to the base.DiconnectHandler.

Have in mind that the DisconnectHandler should not be called normally in projects targeting <.Net 9 (i.e. in .NET 8). This is only happening in .NET 9, and you can opt out by using the following attached property on the control: HandlerProperties.DisconnectPolicy="Manual"

protected override void DisconnectHandler(MauiMKMapView platformView) { platformView.DidSelectAnnotationView -= CustomMapHandler_DidSelectAnnotationView; platformView.GetViewForAnnotation -= GetViewForAnnotation; platformView.RegionChanged -= PlatformView_RegionChanged; //base.DisconnectHandler(platformView); }

kaniosm avatar Nov 18 '24 10:11 kaniosm

You can disconnect the handler in xaml for your custom handler for .net 9:

<maps:Map
  x:Name="map"
  HandlerProperties.DisconnectPolicy="Manual"
  IsScrollEnabled="False"
  ItemsSource="{Binding Pins}">
</maps:Map>

and in your CustomMapHandler (just for iOS) as I used this example, example:

 protected override void DisconnectHandler(MauiMKMapView platformView)
 {
     platformView.GetViewForAnnotation -= GetViewForAnnotations;
 }

patkozlowski avatar Nov 20 '24 23:11 patkozlowski

FYI, I'm facing another issue with Maps on .NET 9, possibly related to this. The app crashes under some special circumstances with invalid cast exception. More details can be found here:

https://github.com/dotnet/maui/issues/26000

kaniosm avatar Nov 21 '24 06:11 kaniosm

This issue still happens when manipulating MapElements using Microsoft.Maui.Controls.Maps 9.0.40.

This makes the control unusable. Do we have a fix/workaround for this?

EDIT - using HandlerProperties.DisconnectPolicy="Manual" does seem to suppress the exception.

dan5602 avatar Mar 13 '25 14:03 dan5602

You can disconnect the handler in xaml for your custom handler for .net 9:

<maps:Map
  x:Name="map"
  HandlerProperties.DisconnectPolicy="Manual"
  IsScrollEnabled="False"
  ItemsSource="{Binding Pins}">
</maps:Map>

and in your CustomMapHandler (just for iOS) as I used this example, example:

 protected override void DisconnectHandler(MauiMKMapView platformView)
 {
     platformView.GetViewForAnnotation -= GetViewForAnnotations;
 }

@patkozlowski The HandlerProperties.DisconnectPolicy="Manual" change has stopped the app from crashing so far. I it also necessary to override the disconnect handler? Not sure what that is accomplishing.

ckrutsinger avatar May 12 '25 19:05 ckrutsinger

Thank you @patkozlowski for the solution, it works by setting the disconnectpolicy to manual. We create a map in the code and add it to the xaml, so for anyone using the same route, we set the policy as follows:

_map.SetValue(Microsoft.Maui.Controls.HandlerProperties.DisconnectPolicyProperty, Microsoft.Maui.HandlerDisconnectPolicy.Manual);

corne-ac avatar May 21 '25 08:05 corne-ac