Friday, 15 January 2010

MonoTouch MapKit.Delegate-precated

An update to MonoTouch (1.4.4) was released today with these changes/improvements (actually 1.4.5 was released a day later). One in particular caught my eye, since I've previously blogged about MapKit in MonoTouch.
MKMapView now has C# style events

So what does that mean? Basically the crafty team at Novell have turned the Apple SDK "pattern" of using a MKMapViewDelegate class to respond to "events" on its head, and instead exposed familiar .NET events on MKMapView itself. *

Here's a comparison of the 'old' and 'new' MKMapView class:


Here are two 'example' delegate methods that work in 1.4.4 (and .5). Firstly here's an example of wiring up one of the "new" events CalloutAccessoryControlTapped. NOTE the += used to attach the delegate to the event.
Map.CalloutAccessoryControlTapped += 
delegate(object sender, MKMapViewAccessoryTappedEventArgs e)
{
MyAnnotation myAnn = e.View.Annotation as MyAnnotation;
using (var alert = new UIAlertView (myAnn.Title,
myAnn.Subtitle + " clicked", null, "OK", null))
{
alert.Show();
}
};
The second example is probably the most common one - GetViewForAnnotation - which you will need to provide if you want to do any sort of customization of your pins/callouts. NOTE how it is assigned with an equals sign and has a return value!
Map.GetViewForAnnotation = delegate (MKMapView mapView, NSObject annotation) {
if (annotation is MKUserLocation) return null;
MyAnnotation myAnn = annotation as MyAnnotation;
var annView = mapView.DequeueReusableAnnotation ("pin");
if (annView == null) {
var pinView = new MKPinAnnotationView(myAnn, "pin");
pinView.AnimatesDrop = true;
pinView.CanShowCallout = true;
annView = pinView;
}
else
{
annView.Annotation = annotation;
}
return annView;
};

* imagine these are "air quotes" in this paragraph
p.s. This post has been updated since the comments below. The first two kinda don't make sense now... Thanks for the advice mdi.

2 comments:

  1. The GetViewForAnnotation property follows a pattern that we have used elsewhere where the property is of the type of a delegate that returns a value.

    The idea is that you can write code like this:

    foo.GetViewForAnnotation = delegate {
    return new UILabel (...);
    }

    ReplyDelete
  2. Of course it does! D'uh. Thx 'mdi' :) I was relying on intellisense for guidance and assigning a delegate didn't occur to me for some reason... Can I nominate CLLocationManager+Delegate for the same treatment? It is much neater and more natural to write (.NET style)

    Map.GetViewForAnnotation = delegate (MKMapView mapView, NSObject annotation) {
    if (annotation is MKUserLocation) return null;
    MyAnnotation myAnn = annotation as MyAnnotation;
    var annView = mapView.DequeueReusableAnnotation ("mypin");
    if (annView == null) {
    var pinView = new MKPinAnnotationView(myAnn, "mypin");
    pinView.AnimatesDrop = true;
    pinView.PinColor = MKPinAnnotationColor.Purple;
    pinView.CanShowCallout = true;
    // Left callout
    UIImage img = UIImage.FromFile("icon.png");
    UIImageView imgView = new UIImageView(img);
    pinView.LeftCalloutAccessoryView = imgView;
    pinView.CanShowCallout = true;
    annView = pinView;
    }
    else
    {
    annView.Annotation = annotation;
    }
    return annView;
    };

    ReplyDelete