Sunday, 27 September 2009

MonoTouch MapKit 103

UPDATE 13-Oct: This code all works in the latest version of MonoTouch - v1.1 - on devices AND in the simulator. You can download a MonoDevelop solution or view the c# files:UPDATE 28-Sep:confirmation from Geoff that the problem with the Simulator should be fixed in 1.1, coming soon...

Once again thanks to a hint from Geoff, I've pieced a little more of MapKit together. This has been tested with RC2 of MonoTouch. The trick? It ONLY WORKS ON THE DEVICE - the simulator will 'crash' with the Stack Trace shown at the bottom of this post (I'm sure this will be fixed in a future release).



This code in FinishedLaunching
Once again, use the 'new' AddAnnotationObject method.
mapView.Delegate = new MapViewDelegate(this);
MyAnnotation a = new MyAnnotation(
new CLLocationCoordinate2D(-33.867139,151.207114)
, "Home"
, "is where the heart is"
);
Console.WriteLine(" ### This breaks in the simulator BUT it works on device!!!");
mapView.AddAnnotationObject(a);
with this MKAnnotation subclass
In MonoTouch MKAnnotation is an abstract class, but in ObjectiveC it's a @protocol. This kinda explains why everything in the class is read-only - @protocols are akin to interfaces in C#, but they cannot be "modelled" as interfaces in MonoTouch because @protocols members can be optional! The simplest way to get an annotation is therefore this implementation (although I think you could also create your own subclass of NSObject and Export() the MKAnnotation members manually).
public class MyAnnotation : MKAnnotation
{
private CLLocationCoordinate2D _coordinate;
private string _title, _subtitle;
public override CLLocationCoordinate2D Coordinate {
get { return _coordinate; }
}
public override string Title {
get { return _title; }
}
public override string Subtitle {
get { return _subtitle; }
}
/// <summary>
/// Need this constructor to set the fields, since the public
/// interface of this class is all READ-ONLY
/// <summary>
public MyAnnotation (CLLocationCoordinate2D coord,
string t, string s) : base()
{
_coordinate=coord;
_title=t;
_subtitle=s;
}
}
and this MKMapViewDelegate implementation
public class MapViewDelegate : MKMapViewDelegate
{
private AppDelegate _appd;
public MapViewDelegate (AppDelegate appd):base()
{
_appd = appd;
}
///
/// When user moves the map, update lat,long text in label
///

public override void RegionChanged
(MKMapView mapView, bool animated)
{
Console.WriteLine("Region did change");
_appd.labelCurrent.Text = "Map Center "
+ mapView.CenterCoordinate.Latitude + ", "
+ mapView.CenterCoordinate.Longitude;
}
///
/// Seems to work in the Simulator now
///

public override MKAnnotationView GetViewForAnnotation
(MKMapView mapView, NSObject annotation)
{
var anv = mapView.DequeueReusableAnnotation("thislocation");
if (anv == null)
{
Console.WriteLine("creating new MKAnnotationView");
anv = new MKPinAnnotationView(annotation, "thislocation");
}
else
{
anv.Annotation = annotation;
}
anv.AnimatesDrop = true;
anv.PinColor = MKPinAnnotationColor.Green;
anv.CanShowCallout = true;
return anv;
}
}

This Stack Trace (below) is what you'll see in MonoDevelop when using the Simulator - upload to the device to get it working (or if you are using the trial version, you may have to wait for an update to MonoTouch). UPDATE:fixed in MonoTouch 1.1
  at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr) <0x00004>
at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr)
at MonoTouch.UIKit.UIApplication.Main (string[],string,string)
at MonoTouch.UIKit.UIApplication.Main (string[])
at MapKit01.Application.Main (string[])
at (wrapper runtime-invoke) .runtime_invoke_void_object (object,intptr,intptr,intptr)
Native stacktrace:
0 MapKit01 0x00092d1a mono_handle_native_sigsegv + 266
1 MapKit01 0x00006f3a mono_sigsegv_signal_handler + 298
2 libSystem.B.dylib 0x90b25b9b _sigtramp + 43
3 ??? 0xffffffff 0x0 + 4294967295
Debug info from gdb:
warning: Trying to remove a section from the ordered section list that did not exist at 0x2d4000.

13 comments:

  1. Can you pls post the entire sln?

    ReplyDelete
  2. I'm happy to report that, having tried the above code with MonoTouch 1.1 (just released on the MonoTouch website), it works :)

    ReplyDelete
  3. I am getting errors that these properties do not exist:

    //anv.AnimatesDrop = true
    //anv.PinColor = MKPinAnnotationColor.Green;

    ReplyDelete
  4. its a nice article... i just tried some funstuff with mapkit and it works fine. I have a small issue, i want to get Bounding Region of the map in LatLongs.I think with MKMapView Class's Region property i can get it but i don't know how to make correct region using Center Point and Span.

    ReplyDelete
  5. I got 2 error while compiling the source.

    It said:
    MapKit01.AppDelegate.MyAnnotation.coordinate' is marked as an override but no suitable property found to override

    MapKit01.AppDelegate.MapViewDelegate.GetViewForAnnotation(MonoTouch.MapKit.MKMapView, MonoTouch.MapKit.MKAnnotation)': cannot override because `MonoTouch.MapKit.MKMapViewDelegate.GetViewForAnnotation(MonoTouch.MapKit.MKMapView, MonoTouch.Foundation.NSObject)' is not a method

    I'm using MonoTouch 1.1 and the latest MonoDevelop 2.2.1

    ReplyDelete
  6. Post has been updated with a MonoDevelop solution that works with MonoTouch 1.1 - MapKit03.zip.

    ReplyDelete
  7. hihi....i've downloaded the MapKit03.zip to learn about the mapkit...but When I compiled it, it told me that there was an error :

    `MapKit01.AppDelegate.MyAnnotation' does not implement inherited abstract member `MonoTouch.MapKit.MKAnnotation.Coordinate.set' (CS0534) (MapKit03)

    Should I do any modifications ?

    ReplyDelete
  8. Yes - the example is over one year old! Your MKAnnotation subclass should include both get and set for the Coordinate property.


    private CLLocationCoordinate2D coordinate;

    public override CLLocationCoordinate2D Coordinate
    {
    get { return coordinate; }
    set { coordinate = value; } // required for iOS 3.2/4.0
    }

    ReplyDelete
  9. how to set multiple coordinates in a single view?

    ReplyDelete
  10. This drawing on maps with monotouch also contains examples of adding multiple pins to a map. Also there is a whole chapter on Mapping in my book

    ReplyDelete
  11. Thank you very much,
    but my requirement is to show multiple addresses (contacts) in a single view without any lines between addresses.

    ReplyDelete
  12. When I try and use your "MyAnnotation" class I get this error:

    .MyAnnotation' does not implement inherited abstract member `MonoTouch.MapKit.MKAnnotation.Coordinate.set' (CS0534)

    ReplyDelete
  13. Jack, unfortunately the base class has changed since this blogpost - you must now implement the 'set' as well. See the comment above from 22-Oct-2010, your MyAnnotation class needs this:

    private CLLocationCoordinate2D coordinate;

    public override CLLocationCoordinate2D Coordinate
    {
    get { return coordinate; }
    set { coordinate = value; } // required for iOS 3.2/4.0
    }

    ReplyDelete