Как мне решить проблему с ошибкой регистрация события перезаписывает существующий делегат для MKMapView?

#xamarin #xamarin.forms #xamarin.ios #mkmapviewdelegate

#xamarin #xamarin.forms #xamarin.ios #mkmapviewdelegate

Вопрос:

Когда я пытаюсь запустить свое приложение Xamarin.forms maps, я получаю следующую ошибку: регистрация события перезаписывает существующий делегат. Либо просто используйте events, либо свой собственный делегат: MyApp.iOS.CustomRenderer.MapDelegate MapKit.MKMapView _MKMapViewDelegate Я прикрепил свой файл CustomMapRender к этому вопросу

… C#

     using ICCHMapClusterControllerDelegate =           MapClustering.ICCHMapClusterControllerDelegate;
    using ICCHMapClusterer = MapClustering.ICCHMapClusterer;

    [assembly: ExportRenderer(typeof(CustomMap),   typeof(CustomMapRenderer))]
     namespace MyApp.iOS.CustomRenderer
    {
          public class CustomMapRenderer : MapRenderer, ICCHMapClusterControllerDelegate//IMKMapViewDelegate
{
    MKMapView mapView;
    CustomMap customMap;
    CCHMapClusterController mapClusterController;
    ICCHMapClusterer mapClusterer;
    List<MKPointAnnotation> annotations;
    CLLocationManager LocationManager;

    protected override void Dispose(bool disposing)
    {
        mapView.ShowsUserLocation = false;
        base.Dispose(disposing);
    }

    protected override void OnElementChanged(ElementChangedEventArgs<View> e)
    {
        base.OnElementChanged(e);
        if (e.OldElement == null)
        {

            mapView = Control as MKMapView;
            customMap = e.NewElement as CustomMap;
            customMap.LocationsLoaded  = customMap_LocationsLoaded;
            customMap.CenterToMyLocationButtonClicked  = CenterToMyLocation;
            customMap.OpenCallout  = OpenCallout;
            LocationManager = new CLLocationManager();

            LocationManager.AuthorizationChanged  = (object locationmanager, CLAuthorizationChangedEventArgs eventargs) =>
            {
                if (eventargs.Status == CLAuthorizationStatus.AuthorizedWhenInUse)
                {
                    mapView.ShowsUserLocation = true;
                }
                else
                {
                    mapView.ShowsUserLocation = false;
                }
            };

            if (CLLocationManager.Status == CLAuthorizationStatus.AuthorizedWhenInUse || CLLocationManager.Status == CLAuthorizationStatus.AuthorizedAlways
                || CLLocationManager.Status == CLAuthorizationStatus.Authorized)
            {
                mapView.ShowsUserLocation = true;
            }

            WMSTileOverlay WMSOverlay = new WMSTileOverlay(NetworkConstants.WmsOvermaasLayerUrl, "3")
            {
                CanReplaceMapContent = false
            };

            WMSProvincieTileOverlay ProvinceOverLay = new WMSProvincieTileOverlay
            {
                CanReplaceMapContent = false
            };

            WMSTileOverlay WPMOverlay2 = new WMSTileOverlay(NetworkConstants.WmsWpmLayerUrl, "2")
            {
                CanReplaceMapContent = false
            };

            WMSTileOverlay WPMOverlay3 = new WMSTileOverlay(NetworkConstants.WmsWpmLayerUrl, "3")
            {
                CanReplaceMapContent = false
            };

            WMSTileOverlay WPMOverlay4 = new WMSTileOverlay(NetworkConstants.WmsWpmLayerUrl, "4")
            {
                CanReplaceMapContent = false
            };

            mapView.AddOverlay(WMSOverlay, MKOverlayLevel.AboveLabels);
            mapView.AddOverlay(ProvinceOverLay, MKOverlayLevel.AboveLabels);
            mapView.AddOverlay(WPMOverlay2, MKOverlayLevel.AboveLabels);
            mapView.AddOverlay(WPMOverlay3, MKOverlayLevel.AboveLabels);
            mapView.AddOverlay(WPMOverlay4, MKOverlayLevel.AboveLabels);

            Debug.WriteLine("TESTING");

            mapClusterController = new CCHMapClusterController(mapView);

            mapClusterController.Delegate = new CCHMapClusterControllerDelegate();
            mapClusterController.WeakDelegate = this;
            // /new CCHMapDelegate();//new CCHMapDelegate();
            //new CCHMapClusterControllerDelegate(); //new CCHMapDelegate ();

        }
    }

    private void customMap_LocationsLoaded(object sender, List<Location> locations)
    {
        RemoveAnnotations();
        if (locations == null || locations.Count == 0)
        {
            return;
        }
        annotations = new List<MKPointAnnotation>();
        foreach (Location location in locations)
        {
            MKPointAnnotation anno = new MKPointAnnotation();
            CLLocationCoordinate2D coord = new CLLocationCoordinate2D(location.Latitude, location.Longitude);
            anno.Coordinate = coord;
            anno.Title = location.WaterName;
            anno.Subtitle = location.City   " "   location.ExternalReference;
            annotations.Add(anno);
        }

        mapClusterController.AddAnnotations(annotations.ToArray(), null);
        mapView.Delegate = new MapDelegate(locations, customMap);
        mapClusterController.ReuseExistingClusterAnnotations = false;
    }

    private void RemoveAnnotations()
    {
        if (annotations != null amp;amp; annotations.Count != 0)
        {
            mapClusterController.RemoveAnnotations(annotations.ToArray(), () =>
            {
            });
        }
    }

    private void CenterToMyLocation(object sender, string e)
    {
        if (CLLocationManager.Status == CLAuthorizationStatus.AuthorizedWhenInUse || CLLocationManager.Status == CLAuthorizationStatus.AuthorizedAlways
            || CLLocationManager.Status == CLAuthorizationStatus.Authorized)
        {
            MKCoordinateRegion mapRegion;
            mapRegion.Center.Latitude = mapView.UserLocation.Coordinate.Latitude;
            mapRegion.Center.Longitude = mapView.UserLocation.Coordinate.Longitude;
            mapRegion.Span.LatitudeDelta = 0.2;
            mapRegion.Span.LongitudeDelta = 0.2;
            mapView.SetRegion(mapRegion, true);
        }
        if (CLLocationManager.Status == CLAuthorizationStatus.Denied)
        {
            //check if ios 7/8 this is ios 8
            UIAlertController alertController = UIAlertController.Create(title: "Locatie", message: "Om uw locatie te kunnen gebruiken in de app hebben we uw toestemming nodig. "  
                                "dit kunt u in het instellingen menu geven.", preferredStyle: UIAlertControllerStyle.Alert);

            alertController.AddAction(UIAlertAction.Create(title: "Annuleren", style: UIAlertActionStyle.Cancel, handler: null));
            alertController.AddAction(UIAlertAction.Create(title: "Instellingen", style: UIAlertActionStyle.Default, handler =>
            {
                NSUrl settingsurl = new NSUrl(UIApplication.OpenSettingsUrlString);
                mapView.ShowsUserLocation = true;
                UIApplication.SharedApplication.OpenUrl(settingsurl);
            }));

            UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(alertController, true, null);


            //Old Obsolete

            //UIAlertView alert = new UIAlertView("Locatie", "Om uw locatie te kunnen gebruiken in de app hebben we uw toestemming nodig. "  
            // "dit kunt u in het instellingen menu geven.", null, "Annuleren", "Instellingen");



            //alert.Clicked  = (object alertsender, UIButtonEventArgs eventargs) => {
            //    if (eventargs.ButtonIndex != 0)
            //    {
            //        NSUrl settingsurl = new NSUrl(UIApplication.OpenSettingsUrlString);
            //        mapView.ShowsUserLocation = true;
            //        UIApplication.SharedApplication.OpenUrl(settingsurl);
            //    }
            //};
            //alert.Show();
        }
        if (CLLocationManager.Status == CLAuthorizationStatus.NotDetermined)
        {
            LocationManager.RequestWhenInUseAuthorization();
        }
    }

    private void OpenCallout(object sender, Location e)
    {
        System.Threading.Tasks.Task.Factory.StartNew(() =>
        {
            Thread.Sleep(1000); // delay execution for 1 s
            Device.BeginInvokeOnMainThread(() =>
            {
                var anno = this.annotations.Where(a => a.Coordinate.Latitude == e.Latitude amp;amp; a.Coordinate.Longitude == e.Longitude).FirstOrDefault();
                if (anno != null)
                {
                    this.mapClusterController.SelectAnnotation(anno, e.Latitude, e.Longitude);
                }
            });
        });
    }

    [Export("mapClusterController:titleForMapClusterAnnotation:")]
    public string TitleForMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
    {

        var annotationsCount = mapClusterAnnotation.Annotations.Count;
        if (annotationsCount != 1) return "";
        MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First();
        return annot.Title;
    }


    [Export("mapClusterController:subtitleForMapClusterAnnotation:")]
    public string SubtitleForMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
    {
        if (mapClusterAnnotation.Annotations.Count != 1) return "";
        MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First();
        return annot.Subtitle;
    }

    [Export("mapClusterController:willReuseMapClusterAnnotation:")]
    public void WillReuseMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)

    {

    }
}


internal class MapDelegate : MKMapViewDelegate
{
    public MapDelegate(List<Location> locations, CustomMap CustomMap)
        : base()
    {
        Locations = locations;
        customMap = CustomMap;
        conv = new LevelStatusToColorValueConverter();
        defaultColor = Color.FromHex(ColorConstants.WaterLevelBadgeGreen).ToUIColor();
    }

    static NSObject Invoker = new NSObject();
    List<Location> Locations;
    string clusterPinId = "cluster";
    string nonClusterPinId = "nonCluster";
    CustomMap customMap;
    LevelStatusToColorValueConverter conv;
    UIColor defaultColor;
    public override void RegionChanged(MKMapView mapView, bool animated)
    {
        if (mapView.UserLocationVisible)
        {
            customMap.ChangeStatusOfLocationImageOnMap(true);
        }
        else
        {
            customMap.ChangeStatusOfLocationImageOnMap(false);
        }
    }

    public override MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation anno)
    {
        var annotation = ObjCRuntime.Runtime.GetNSObject(anno.Handle) as CCHMapClusterAnnotation; // this is required to get the underlying annotation object

        string useId = nonClusterPinId;

        if (anno is MKUserLocation)
            return null;
        if (annotation == null)
        {
            return null;
        }

        string imageName = "";
        string imageURL = string.Empty;
        string value = string.Empty;

        UIColor color = defaultColor;
        if (annotation.IsCluster)
        {
            useId = clusterPinId;
            if (Locations != null)
            {
                List<Location> locations = new List<Location>();
                foreach (MKPointAnnotation clusterAnno in annotation.Annotations)
                {
                    string title = clusterAnno.Subtitle;
                    var location = Locations.Where(l => (l.City   " "   l.ExternalReference) == title).ToList();
                    if (location != null amp;amp; location.Count != 0)
                    {
                        locations.Add(location.First());

                    }
                }
                if (locations.Any())
                {
                    imageName = MapUtil.GetCorrectImageNameForLocations(locations);
                }
            }
        }
        else
        {
            if (Locations != null)
            {
                string title = annotation.Subtitle;
                var location = Locations.Where(l => (l.City   " "   l.ExternalReference) == title).ToList();
                if (location != null amp;amp; location.Count != 0)
                {
                    var currentLocation = location.First();
                    value = currentLocation.CurrentValueAsString;
                    var xColor = (Color)conv.Convert(currentLocation.WaterlevelStatus, null, null, null);
                    color = xColor.ToUIColor();
                    imageName = MapUtil.GetCorrectImageNameForLocation(currentLocation);
                    if (currentLocation.HasImage)
                    {
                        imageURL = currentLocation.SmallImageURL();
                    }
                    else
                    {
                        imageURL = NetworkConstants.NoImageSmall;
                    }
                }
            }
        }

        MKAnnotationView pinView = (MKAnnotationView)mapView.DequeueReusableAnnotation(useId);

        if (pinView == null)
            pinView = new MKAnnotationView(annotation, useId);

        if (!annotation.IsCluster)
        {
            pinView.CanShowCallout = true;
            double testWidth = value.Length < 11 ? 65 : 90;
            var button = new UIButton(new CGRect(testWidth, 5, 10, 20));
            button.SetImage(UIImage.FromBundle("disclosure"), UIControlState.Normal);
            JSBadgeView badge = new JSBadgeView(button, JSBadgeView.Alignment.CenterLeft)
            {
                BadgeBackgroundColor = color,
                BadgeStrokeColor = UIColor.Red,
                BadgeTextColor = Color.FromHex(ColorConstants.DarkGreyDetailText).ToUIColor(),
                BadgeTextFont = UIFont.FromName("AvenirNext-Regular", 11),
                BadgeAlignment = JSBadgeView.Alignment.CenterLeft,
                BadgeText = value
            };
            UIView view = new UIView(new CGRect(0, 0, testWidth   10, 30));
            view.ClipsToBounds = false;
            view.AddSubview(button);
            pinView.RightCalloutAccessoryView = view;
            if (string.IsNullOrEmpty(imageURL))
            {
                var imageView = new UIImageView(new CGRect(0, 0, 42, 42));
                imageView.Image = UIImage.FromBundle("notavailable");
                imageView.ContentMode = UIViewContentMode.ScaleAspectFit;
                pinView.LeftCalloutAccessoryView = imageView;
            }
            else
            {
                FromUrl(imageURL, pinView);
            }
        }
        pinView.Image = UIImage.FromBundle((string.IsNullOrEmpty(imageName)) ? "flowgreenpin" : imageName);
        if (annotation.IsCluster)
        {
            pinView.CanShowCallout = false;
            JSBadgeView badge = new JSBadgeView(pinView, JSBadgeView.Alignment.TopCenter)
            {
                BadgeBackgroundColor = UIColor.FromRGB(0.451f, 0.847f, 0.988f),
                BadgeStrokeColor = UIColor.Red,
                BadgeTextColor = UIColor.White,
                BadgeTextFont = UIFont.FromName("AvenirNext-Regular", 11),
                BadgeAlignment = JSBadgeView.Alignment.TopCenter,
                BadgeText = annotation.Annotations.Count.ToString()
            };
        }
        return pinView;
    }

    public static void InvokedOnMainThread(Action Action)
    {
        if (NSThread.Current.IsMainThread)
            Action();
        else
            Invoker.BeginInvokeOnMainThread(() => Action());
    }

    static async Task FromUrl(string uri, MKAnnotationView pinView)
    {

        using (var httpClient = new HttpClient())
        {

            Task<byte[]> contentsTask = httpClient.GetByteArrayAsync(uri);

            // await! control returns to the caller and the task continues to run on another thread
            var contents = await contentsTask;

            // load from bytes
            var image = UIImage.LoadFromData(NSData.FromArray(contents));
            var imageView = new UIImageView(new CGRect(0, 0, 42, 42));
            imageView.Image = image;
            imageView.ContentMode = UIViewContentMode.ScaleAspectFit;
            InvokedOnMainThread(delegate
            {
                pinView.LeftCalloutAccessoryView = imageView;
            });
        }
    }

    public override void DidSelectAnnotationView(MKMapView mapView, MKAnnotationView view)
    {
        var annotation = ObjCRuntime.Runtime.GetNSObject(view.Annotation.Handle) as CCHMapClusterAnnotation;
        if (annotation != null)
        {
            if (!annotation.IsCluster)
            {
                UITapGestureRecognizer tap = new UITapGestureRecognizer(OnTap);
                view.AddGestureRecognizer(tap);
                return;
            }
            MKMapRect mapRect = annotation.MapRect;
            UIEdgeInsets edgeInsets = new UIEdgeInsets(20, 20, 20, 20);
            mapView.SetVisibleMapRect(mapRect, edgeInsets, true);
        }
        mapView.DeselectAnnotation(view.Annotation, true);
    }

    public override void DidDeselectAnnotationView(MKMapView mapView, MKAnnotationView view)
    {
        view.GestureRecognizers = null;
    }
    public override void CalloutAccessoryControlTapped(MKMapView mapView, MKAnnotationView view, UIControl control)
    {
        if (view != null)
        {
            var clusterPin = ObjCRuntime.Runtime.GetNSObject(view.Annotation.Handle) as CCHMapClusterAnnotation;
            var location = Locations.Where(l => (l.City   " "   l.ExternalReference) == clusterPin.Subtitle).ToList();
            if (location != null amp;amp; location.Count != 0)
            {
                customMap.ClickedCallout(location.First());
            }
        }
    }
    private void OnTap(UIGestureRecognizer gesture)
    {
        var pinView = gesture.View as MKAnnotationView;
        if (pinView != null)
        {
            var clusterPin = ObjCRuntime.Runtime.GetNSObject(pinView.Annotation.Handle) as CCHMapClusterAnnotation;
            var location = Locations.Where(l => (l.City   " "   l.ExternalReference) == clusterPin.Subtitle).ToList();
            if (location != null amp;amp; location.Count != 0)
            {
                customMap.ClickedCallout(location.First());
            }
        }
    }

    public override MKOverlayRenderer OverlayRenderer(MKMapView mapView, IMKOverlay overlay)
    {
        var osmOverlay = overlay as WMSTileOverlay;
        if (osmOverlay != null)
        {
            return new MKTileOverlayRenderer(new WMSTileOverlay(osmOverlay.BaseUrl, osmOverlay.Layer) { CanReplaceMapContent = false });
        }
        return new MKTileOverlayRenderer(new WMSProvincieTileOverlay() { CanReplaceMapContent = false });
    }
}

internal class CCHMapDelegate : UIViewController, ICCHMapClusterControllerDelegate//CCHMapClusterControllerDelegate
{

    [Export("mapClusterController:titleForMapClusterAnnotation:")]
    public string TitleForMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
    {

        var annotationsCount = mapClusterAnnotation.Annotations.Count;
        if (annotationsCount != 1) return "";
        MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First();
        return annot.Title;
    }
    //public override string MapClusterTitleForAnnotation (CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
    //{
    //  if (mapClusterAnnotation.Annotations.Count == 1) {
    //      MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First ();
    //      return annot.Title;
    //  }
    //  return "";
    //}

    [Export("mapClusterController:subtitleForMapClusterAnnotation:")]
    public string SubtitleForMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
    {
        if (mapClusterAnnotation.Annotations.Count != 1) return "";
        MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First();
        return annot.Subtitle;
    }
    //public override string MapClusterSubtitleForAnnotation (CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
    //{
    //  if (mapClusterAnnotation.Annotations.Count == 1) {
    //      MKPointAnnotation annot = (MKPointAnnotation)mapClusterAnnotation.Annotations.First ();
    //      return annot.Subtitle;
    //  }
    //  return "";
    //}


    [Export("mapClusterController:willReuseMapClusterAnnotation:")]

    public void WillReuseMapClusterAnnotation(CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)

    {

    }

    //public override void MapClusterWillReuseAnnotation (CCHMapClusterController mapClusterController, CCHMapClusterAnnotation mapClusterAnnotation)
    //{
    //}



}
}
  

Комментарии:

1. Вы не можете смешивать обработчики событий C # map и использовать свои собственные MapDelegate : MKMapViewDelegate поскольку Xamarin уже использует свой собственный делегат для предоставления обработчиков событий в стиле C #

2. Здравствуйте, не могли бы вы указать мне на более конкретное решение. Кажется, я не могу это исправить