public void displayCallout(IMapAnnotation annotation, IAnnotationMarker annotationElement)
        {
            // Hide any existing callout
            hideCallout();

            // There is only ever one callout
            MapCallout callout = new MapCallout();
            calloutLayer.Children.Add(callout);

            // Hook up tap event
            callout.Callout_Tapped += callout_Callout_Tapped;

            // Assign this annotation as the data context of the callout - so it can get Title, Subtitle, etc
            callout.DataContext = annotation;

            // Position
            MapLayer.SetPosition(callout, new Location(annotation.Latitude, annotation.Longitude));

            // Callout anchor point also depends upon the anchor of the pushpin
            MapLayer.SetPositionAnchor(callout, new Windows.Foundation.Point(
                CALLOUT_ANCHOR_X + annotationElement.PositionAnchor.X,
                CALLOUT_ANCHOR_Y + annotationElement.PositionAnchor.Y));

            // Appear

            callout.animateOnscreen();

            Point offsetRequired;
            if (!isCalloutInView(callout, out offsetRequired))
                map.scrollBy(offsetRequired);

            // Store for later
            lastCallout = callout;
        }
        // Helpers
        bool isCalloutInView(MapCallout callout, out Point offsetRequired)
        {
            offsetRequired = new Point();
            Location calloutLocation = MapLayer.GetPosition(callout);
            Point calloutTranslation = MapLayer.GetPositionAnchor(callout);

            Point calloutPixelLocation;
            if (!map.TryLocationToPixel(calloutLocation, out calloutPixelLocation))
                throw new Exception("Cannot get location of callout ");

            // Where is the callout?

            Point calloutTopLeftLocation = new Point(calloutPixelLocation.X - calloutTranslation.X, calloutPixelLocation.Y - calloutTranslation.Y);
            Rect calloutRect = new Rect(calloutTopLeftLocation, new Size(MapConstants.CalloutWidth, MapConstants.CalloutHeight));

            // Work out if it is within the map boundary
            double offsetXRequired = 0;
            double offsetYRequired = 0;
            double mapWidth = map.ActualWidth;
            double mapHeight = map.ActualHeight;
            if (calloutRect.Left < 0)
                offsetXRequired = (0 - calloutRect.Left);
            else if (calloutRect.Right > mapWidth)
                offsetXRequired = (mapWidth - calloutRect.Right);
            if (calloutRect.Top < 0)
                offsetYRequired = (0 - calloutRect.Top);
            else if (calloutRect.Bottom > mapHeight)
                offsetYRequired = (mapHeight - calloutRect.Bottom);

            offsetRequired = new Point(offsetXRequired, offsetYRequired);

            return (offsetXRequired == 0) && (offsetYRequired == 0);
        }
        public void hideCallout()
        {
            if (lastCallout == null) return;

            // Unhook tapped event
            lastCallout.Callout_Tapped -= callout_Callout_Tapped;

            // Animate disappearance
            lastCallout.Callout_Disappeared += lastCallout_Callout_Disappeared;
            lastCallout.animateOffscreen();
            lastCallout = null;
        }