medvedo medvedo - 1 month ago 8
C# Question

Trying to add multiple customPins on my CustomMap in Xamarin.Forms.iOS

XAML:

<local:CustomMap x:Name="mymap" MapType="Street" IsShowingUser="true"/>


Code:

var pin = new CustomPin ();
pin.MapPin.Label = "Test";
pin.MapPin.Position = new Position(32, 10);
pin.MapPin.Label = "1";
pin.MapPin.Address = "394 Pacific Ave, San Francisco CA";
pin.Id = "Xamarin";

pin = new CustomPin ();
pin.MapPin.Label = "Test2";
pin.MapPin.Position = new Position(33, 10);
pin.MapPin.Label = "2";
pin.MapPin.Address = "394 Pacific Ave, San Francisco CA";
pin.Id = "Xamarin";

mymap.CustomPins = new List<CustomPin> { pin };
mymap.Pins.Add (pin.MapPin);


With this code I only get one pin on the map and the pin is the latest one I created so in this case "Test2".
How do I adjust the code so I can add multiple pins?

CustomMap:

public class CustomMap : Map
{
public MapContentType ContentType { get; set; }
public double CircleRadius { get; set; }

public List<Position> Positions { get; set; }

public List<CustomPin> CustomPins { get; set;}

public CustomCircle Circle { get; set; }

public CustomMap()
{
this.ContentType = MapContentType.Normal;
this.CircleRadius = 500;
this.Positions = new List<Position> ();
}

}


CustomPin:

public class CustomPin
{
public CustomPin() {
MapPin = new Pin();
}
public string Id { get; set; }
public EventHandler Url { get; set; }
public Pin MapPin { get; set; }
}


Custom renderer:

public class CustomMapRenderer : MapRenderer
{
MKPolylineRenderer polylineRenderer;

UIView customPinView;

List<CustomPin> customPins;

MKCircleRenderer circleRenderer;

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

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

nativeMap.GetViewForAnnotation = null;

nativeMap.GetViewForAnnotation = null;
nativeMap.DidSelectAnnotationView -= OnDidSelectAnnotationView;
nativeMap.DidDeselectAnnotationView -= OnDidDeselectAnnotationView;




}

if (e.NewElement != null) {
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MKMapView;


customPins = formsMap.CustomPins;
nativeMap.GetViewForAnnotation = GetViewForAnnotation;


nativeMap.GetViewForAnnotation = GetViewForAnnotation;
nativeMap.DidSelectAnnotationView += OnDidSelectAnnotationView;
nativeMap.DidDeselectAnnotationView += OnDidDeselectAnnotationView;



nativeMap.OverlayRenderer = GetOverlayRenderer;

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

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

var routeOverlay = MKPolyline.FromCoordinates (coords);
nativeMap.AddOverlay (routeOverlay);
}


}

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

}
return polylineRenderer;

}

string pId = "PinAnnotation";

MKAnnotationView GetViewForAnnotation (MKMapView mapView, IMKAnnotation annotation)
{
MKAnnotationView annotationView = null;

if (annotation is MKUserLocation)
return null;

var anno = annotation as MKPointAnnotation;
var customPin = GetCustomPin (anno);
if (customPin == null) {
throw new Exception ("Custom pin not found");
}

MKAnnotationView pinView = (MKPinAnnotationView)mapView.DequeueReusableAnnotation (pId);

annotationView = mapView.DequeueReusableAnnotation (customPin.Id);
if (annotationView == null) {
annotationView = new CustomMKPinAnnotationView (annotation, customPin.Id);
annotationView.Image = UIImage.FromFile ("pin.png");
//((MKPinAnnotationView)pinView).PinColor = MKPinAnnotationColor.Green;

annotationView.CalloutOffset = new CGPoint (0, 0);
annotationView.LeftCalloutAccessoryView = new UIImageView (UIImage.FromFile ("monkey.png"));
annotationView.RightCalloutAccessoryView = UIButton.FromType (UIButtonType.DetailDisclosure);
((CustomMKPinAnnotationView)annotationView).Id = customPin.Id;
((CustomMKPinAnnotationView)annotationView).Url = customPin.Url;
}
annotationView.CanShowCallout = true;

return annotationView;
}

void OnDidSelectAnnotationView (object sender, MKAnnotationViewEventArgs e)
{
var customView = e.View as CustomMKPinAnnotationView;
customPinView = new UIView ();

if (customView.Id == "Xamarin") {
customPinView.Frame = new CGRect (0, 0, 200, 84);
var image = new UIImageView (new CGRect (0, 0, 200, 84));
image.Image = UIImage.FromFile ("xamarin.png");
customPinView.AddSubview (image);
customPinView.Center = new CGPoint (0, -(e.View.Frame.Height + 75));
e.View.AddSubview (customPinView);
}
}

void OnDidDeselectAnnotationView (object sender, MKAnnotationViewEventArgs e)
{
if (!e.View.Selected) {
customPinView.RemoveFromSuperview ();
customPinView.Dispose ();
customPinView = null;
}
}

CustomPin GetCustomPin (MKPointAnnotation annotation)
{
var position = new Position (annotation.Coordinate.Latitude, annotation.Coordinate.Longitude);
foreach (var pin in customPins) {
if (pin.MapPin.Position == position) {
return pin;
}
}
return null;
}




}
}

Answer Source

you are getting one pin , because you are adding one pin . you need to know some basics of programming "like changing the properties of an object doesn't create new object "

try this

var pin = new CustomPin ();
    pin.MapPin.Label = "Test";
    pin.MapPin.Position = new Position(32, 10);
    pin.MapPin.Label = "1";
    pin.MapPin.Address = "394 Pacific Ave, San Francisco CA";
    pin.Id = "Xamarin";

   var pin1 = new CustomPin ();
    pin1.MapPin.Label = "Test2";
    pin1.MapPin.Position = new Position(33, 10);
    pin1.MapPin.Label = "2";
    pin1.MapPin.Address = "394 Pacific Ave, San Francisco CA";
    pin1.Id = "Xamarin";

    mymap.CustomPins = new List<CustomPin> { pin,pin1 };
    mymap.Pins.Add (pin.MapPin);
    mymap.Pins.Add (pin1.MapPin);

solution to your problem mentioned in comments,App.Items is a list getting populated from database or webservice(in my case web service) `using

System.Collections.Generic;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using System;

namespace App
{
    public class MapPage : ContentPage
    {
        public  CustomMap customMap1{ get; set;}
        public MapPage ()
        {
            Title ="Stores";
            Icon = "flag_map_marker4.png";


             var customMap = new CustomMap {
                MapType = MapType.Street,
                WidthRequest = App.ScreenWidth,
                HeightRequest = App.ScreenHeight
            };

            customMap.CustomPins = new List<CustomPin>();
            if (App.Items != null && App.Items.Count > 0) {
                foreach (var t in App.Items) {
                    var temp = new CustomPin () {
                        Pin = new Pin () {
                            Label = t.Name,
                            Type = PinType.Place,
                            Position = new Position (t.Lat, t.Lon),
                            Address = t.Address1
                        },
                        Url = t.Link
                    };
                    customMap.CustomPins.Add (temp);
                }
                foreach (var pin in customMap.CustomPins) {
                    customMap.Pins.Add (pin.Pin);
                }
                // dont delete below code ,they will save you if timer doesnt work .

                //var temp1 = new MapSpan(customMap.CustomPins [0].Pin.Position,
//              if(Device.OS == TargetPlatform.iOS)
//              customMap.MoveToRegion (MapSpan.FromCenterAndRadius (customMap.CustomPins [0].Pin.Position, Distance.FromMiles (0.20)));

                if(Device.OS == TargetPlatform.Android)
                customMap.MoveToRegion (MapSpan.FromCenterAndRadius (customMap.CustomPins [0].Pin.Position, Distance.FromMiles (55.0)));
                if (Device.OS == TargetPlatform.iOS) {
                    Device.StartTimer (TimeSpan.FromMilliseconds (500), () => {
                        customMap.MoveToRegion (MapSpan.FromCenterAndRadius (customMap.CustomPins [0].Pin.Position, Distance.FromMiles (55.0)));
                        return false;
                    });
                }
            }

            Content = customMap;
        }

    }


}

` Just ignore the lines which doesn't concern you !