Xamarin.Forms.Maps - Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))

0

I followed the Xamarin Tutorial Customizing a Map. I changed it a bit to be able to draw a route.

public class CustomMap : Map
{
    public static readonly BindableProperty RouteCoordinatesProperty =
    BindableProperty.Create(nameof(RouteCoordinates), typeof(List<Position>), typeof(CustomMap), new List<Position>(), BindingMode.TwoWay);

    public List<Position> RouteCoordinates
    {
        get { return (List<Position>)GetValue(RouteCoordinatesProperty); }
        set { SetValue(RouteCoordinatesProperty, value); }
    }
}

The WinPhone 8.1 renderer:

[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace PROJECT.WinPhone
{
public class CustomMapRenderer : MapRenderer
{
    MapControl nativeMap;
    CustomMap formsMap;

    protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
    {
        base.OnElementChanged(e);

        if (e.OldElement != null)
        {
            nativeMap = Control as MapControl;
        }

        if (e.NewElement != null)
        {
            formsMap = (CustomMap)e.NewElement;
            nativeMap = Control as MapControl;
            //UpdatePolyLine();

            var coordinates = new List<BasicGeoposition>();
            foreach (var position in formsMap.RouteCoordinates)
            {
                coordinates.Add(new BasicGeoposition() { Latitude = position.Latitude, Longitude = position.Longitude });
            }

            var polyline = new MapPolyline();
            polyline.StrokeColor = Windows.UI.Color.FromArgb(128, 255, 0, 0);
            polyline.StrokeThickness = 5;
            polyline.Path = new Geopath(coordinates);
            nativeMap.MapElements.Add(polyline);
        }
    }
}
}

polyline.Path = new Geopath(coordinates); throws Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED)) The problem is that my two others renderer (Android & iOS) works.. Maybe something isn't possible because I work with WinPhone8.1 unlike the tutorial, which is UWP

AndroidRenderer

[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace PROJECT.Droid
{
public class CustomMapRenderer : MapRenderer, IOnMapReadyCallback
{
    GoogleMap map;
    Polyline polyline;

    protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Xamarin.Forms.View> e)
    {
        base.OnElementChanged(e);

        if (e.OldElement != null)
        {
            // Unsubscribe
        }

        if (e.NewElement != null)
        {
            ((MapView)Control).GetMapAsync(this);
        }

        UpdatePolyLine();
    }

    protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);
        if (this.Element == null || this.Control == null)
            return;

        if (e.PropertyName == CustomMap.RouteCoordinatesProperty.PropertyName)
        {
            UpdatePolyLine();
        }
    }

    private void UpdatePolyLine()
    {
        if (map != null)
        {
            if (polyline != null)
            {
                polyline.Remove();
                polyline.Dispose();
            }
            var polylineOptions = new PolylineOptions();
            polylineOptions.InvokeColor(0x66FF0000);

            int a = 0;

            foreach (var position in ((CustomMap)this.Element).RouteCoordinates)
            {
                polylineOptions.Add(new LatLng(position.Latitude, position.Longitude));
            }

            polyline = map.AddPolyline(polylineOptions);
        }
    }

    public void OnMapReady(GoogleMap googleMap)
    {
        map = googleMap;
        UpdatePolyLine();
    }
}
}

iOSRenderer

[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace PROJECT.iOS
{
public class CustomMapRenderer : MapRenderer
{
    MKMapView nativeMap;
    MKPolylineRenderer polylineRenderer;

    protected override void OnElementChanged(ElementChangedEventArgs<View> e)
    {
        base.OnElementChanged(e);

        if (e.OldElement != null)
        {
            nativeMap = Control as MKMapView;
            nativeMap.OverlayRenderer = null;
        }

        if (e.NewElement != null)
        {
            UpdatePolyLine();
        }
    }

    protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);
        if (this.Element == null || this.Control == null)
            return;

        if (e.PropertyName == CustomMap.RouteCoordinatesProperty.PropertyName)
        {
            UpdatePolyLine();
        }
    }

    MKOverlayRenderer GetOverlayRenderer(MKMapView mapView, IMKOverlay overlay)
    {
        if (polylineRenderer == null)
        {
            polylineRenderer = new MKPolylineRenderer(overlay as MKPolyline);
            polylineRenderer.FillColor = UIColor.Blue;
            polylineRenderer.StrokeColor = UIColor.Red;
            polylineRenderer.LineWidth = 3;
            polylineRenderer.Alpha = 0.4f;
        }
        return polylineRenderer;
    }

    private void UpdatePolyLine()
    {
        if (nativeMap != null)
        {
            var formsMap = ((CustomMap)this.Element);
            nativeMap = Control as MKMapView;

            nativeMap.OverlayRenderer = GetOverlayRenderer;

            CLLocationCoordinate2D[] coords = new CLLocationCoordinate2D[formsMap.RouteCoordinates.Count];

            int index = 0;
            foreach (var position in formsMap.RouteCoordinates)
            {
                coords[index] = new CLLocationCoordinate2D(position.Latitude, position.Longitude);
                index++;
            }

            var routeOverlay = MKPolyline.FromCoordinates(coords);
            nativeMap.AddOverlay(routeOverlay);
        }
    }
}
}
exception
maps
xamarin.forms
asked on Stack Overflow Jun 16, 2016 by Emixam23

1 Answer

0

After a long time, I found why it didn't works...

If you're doing like me, if you do a HttpRequest to something as Google Direction API, then the result will comes after the first passage in the OnElementChanged().

Because formsMap.RouteCoordinates isn't null but empty, the Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED)) is thrown..

This is the good CustomMapRenderer for PolyLine use

using PROJECT;
using PROJECT.UWP;
using System.Collections.Generic;
using Windows.Devices.Geolocation;
using Windows.UI.Xaml.Controls.Maps;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Maps.UWP;
using Xamarin.Forms.Platform.UWP;

[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace PROJECT.UWP
{
    public class CustomMapRenderer : MapRenderer
    {
        MapControl nativeMap;
        CustomMap formsMap;

        protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null)
            {
                nativeMap = Control as MapControl;
            }

            if (e.NewElement != null)
            {
                formsMap = (CustomMap)e.NewElement;
                nativeMap = Control as MapControl;
                UpdatePolyLine();
            }
        }

        protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
            if (this.Element == null || this.Control == null)
                return;

            if (e.PropertyName == CustomMap.RouteCoordinatesProperty.PropertyName)
            {
                UpdatePolyLine();
            }
        }

        private void UpdatePolyLine()
        {
            if (formsMap != null && formsMap.RouteCoordinates.Count > 0)
            {
                List<BasicGeoposition> coordinates = new List<BasicGeoposition>();

                foreach (var position in formsMap.RouteCoordinates)
                {
                    coordinates.Add(new BasicGeoposition() { Latitude = position.Latitude, Longitude = position.Longitude });
                }

                Geopath path = new Geopath(coordinates);
                MapPolyline polyline = new MapPolyline();
                polyline.StrokeColor = Windows.UI.Color.FromArgb(128, 255, 0, 0);
                polyline.StrokeThickness = 5;
                polyline.Path = path;
                nativeMap.MapElements.Add(polyline);
            }
        }
    }
}
answered on Stack Overflow Jul 4, 2016 by Emixam23

User contributions licensed under CC BY-SA 3.0