Silverlight VirtualEarth Map Control - #5 (it works!)

After attempts one, two, three and four, all the elements pan and zoom in 'real time' AS DOES the course path (now a MapPolyline) AND the animated Ellipse 'runners'. ALSO, they all scale in 'real time' (from zoomed so far out you can hardly see it to zooming in to street level so that the points are moving very fast indeed).

Making it work...

See #4 for the solutions to most of my problems - the last issue (described below) was animating the Map.Center Location itself.

Animating Map.Center Location (Latitude/Longitude) properties

Unfortunately animating the Map iself was not easy.

Using the same attached properties approach as before to target the Map.Center.Latitude/Longitude properties didn't seem to work, because only one axis would "move" (seemed like the Changed handler was being called for both, but the 'simultaneous' updates caused one to get lost). In the end I have 'synchronised' updating the .Center property with a static field (highlighted in the code below).

Basically your Map tag looks the same as always...

<m:Map x:Name="viewMap" Width="600" Height="800">
   <m:Map.Children>
      <m:MapLayer>

... with the constructor code including the initial Location and a custom Attached Property like this

viewMap.View = new Microsoft.VirtualEarth.MapControl.MapViewSpecification(
                new Location(-33.863502543277534, 151.20294570922852), 15.0000);
 
Storyboard.SetTargetProperty(viewmapanimX, new PropertyPath(Attachments.CenterLatitudeProperty));
Storyboard.SetTargetProperty(viewmapanimY, new PropertyPath(Attachments.CenterLongitudeProperty));

and a seperate static class with the key methods allowing us to animate the otherwise difficult-to-access Latitude/Longitude properties.

#region Map.Center.Latitude
public static readonly DependencyProperty CenterLatitudeProperty =
        DependencyProperty.RegisterAttached("CenterLatitude",
        typeof(double), typeof(Attachments),
        new PropertyMetadata(
            new PropertyChangedCallback(OnCenterLatitudeChanged)));
 
public static void SetCenterLatitude(DependencyObject o, double value)
{
    o.SetValue(CenterLatitudeProperty, value);
}
public static double GetCenterLatitude(DependencyObject o)
{
    return (double)o.GetValue(CenterLatitudeProperty);
}
private static void OnCenterLatitudeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if ((double)e.NewValue == 0.0) return;
    Location l = (Location)((Map)d).Center;
    // l.Latitude = (double)e.NewValue;
    myLatitude = (double)e.NewValue;
    ((Map)d).Center = l;
}
/// <summary>HACK:</summary>
private static double myLatitude = 0.0;
#endregion
#region Map.Center.Longitude
public static readonly DependencyProperty CenterLongitudeProperty =
       DependencyProperty.RegisterAttached("CenterLongitude",
       typeof(double), typeof(Attachments),
       new PropertyMetadata(
           new PropertyChangedCallback(OnCenterLongitudeChanged)));
 
public static void SetCenterLongitude(DependencyObject o, double value)
{
    o.SetValue(CenterLongitudeProperty, value);
}
public static double GetCenterLongitude(DependencyObject o)
{
    return (double)o.GetValue(CenterLongitudeProperty);
}
private static void OnCenterLongitudeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if ((double)e.NewValue == 0.0 || myLatitude == 0.0) return;
    Location l = (Location)((Map)d).Center;
    l.Longitude = (double)e.NewValue;
    l.Latitude = myLatitude; // HACK:
    ((Map)d).Center = l;
}
#endregion

and finally your declarative animation would look like this:

<Canvas.Triggers>
    <EventTrigger RoutedEvent="Canvas.Loaded">
        <BeginStoryboard>
            <Storyboard x:Name="Timeline1">
                <!-- MAP -->
                <DoubleAnimationUsingKeyFrames x:Name="viewmapanimX"
                                            BeginTime="00:00:00"  
                                            Storyboard.TargetName="viewMap">
                    <LinearDoubleKeyFrame KeyTime="00:00:00.000000" Value="-33.863502543277534" />
                    <LinearDoubleKeyFrame KeyTime="00:00:01.109022" Value="-33.8594756365014" />
                    <LinearDoubleKeyFrame KeyTime="00:00:01.570410" Value="-33.8578006724536" />

Useful links

blog post

Download the control

Getting Started with the control

Interactive SDK

Look back at Test #1 Test #2 Test #3 Test #4 and the Silverlight 3.0 beta and even more 3.0 beta fun