Thursday 1 March 2012

WP7 Bing Maps Crash while being led down the garden path!

There I was, innocently trying to data bind to my collection of objects, and use an item template to render them on my maps control for an upcoming application.

So, I added a layer to my map like this:

<my:MapItemsControl x:Name="tracksLayer"
ItemsSource="{Binding Tracks }"
ItemTemplate="{StaticResource TrackTemplate}" />



and implemented my data template like this in the page resources:


<SolidColorBrush x:Key="FadedBrush" Color="Blue" Opacity=".5" />

<DataTemplate x:Name="TrackTemplate">
<MapPolyline Locations="{Binding Locations}"
Stroke="{StaticResource FadedBrush}"
StrokeThickness="5" />
</DataTemplate>



That all worked fine, and I got my brush displayed.


So, I thought great, now lets ask the track what color it should be, and changed the stroke definition to look like this:


<DataTemplate x:Name="TrackTemplate">
<my:MapPolyline Locations="{Binding Locations}"
Stroke="{Binding TrackBrush}"
StrokeThickness="5" />
</DataTemplate>



To my surprise, this threw an exception (or two) and terminated the program.


After a couple hours of debugging to figure out what had happened and being led down the garden path by the StaticResource, I eventually came across the fact that Stroke and StrokeThickness are not dependency properties in MapShapeBase.


Luckily, someone else had solved the problem here.  But be careful, the declarations there aren’t marked public and the dependency properties are implemented differently in WPF, so it won’t work out of the box.


I’ve attached my class here updated for WP7:


public class MapPolylineBindable : MapPolyline
{
public static readonly DependencyProperty StrokeProperty;
public static readonly DependencyProperty StrokeThicknessProperty;

static MapPolylineBindable()
{
MapPolylineBindable.StrokeProperty = DependencyProperty.Register("Stroke", typeof(Brush), typeof(MapPolylineBindable),
new PropertyMetadata(null, OnStrokeExChanged));

MapPolylineBindable.StrokeThicknessProperty = DependencyProperty.Register("StrokeThickness", typeof(double), typeof(MapPolylineBindable),
new PropertyMetadata(1.0, OnStrokeThicknessExChanged));
}

public new Brush Stroke
{
get { return (Brush)GetValue(MapPolylineBindable.StrokeProperty); }
set { SetValue(MapPolylineBindable.StrokeProperty, value); }
}

private static void OnStrokeExChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
(o as MapPolyline).Stroke = (Brush)e.NewValue;
}

public new double StrokeThickness
{
get { return (double)GetValue(MapPolylineBindable.StrokeThicknessProperty); }
set { SetValue(MapPolylineBindable.StrokeThicknessProperty, value); }
}

private static void OnStrokeThicknessExChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
(o as MapPolyline).StrokeThickness = (double)e.NewValue;
}
}

and to bind, you need to do this:

 


<DataTemplate x:Name="TrackTemplate">
<hack:MapPolylineBindable Locations="{Binding Locations}"
Stroke="{Binding TrackBrush}"
StrokeThickness="5" />
</DataTemplate>


No comments:

Post a Comment