I am working on widows phone 8.1 map based application.I want to know how can I draw a map polyline using MVVM pattern. I've already achieved this using the code behind for first creating the polyline and then adding it. My question is can I define a polyline in the XAML itself and give it a source binding to one of my observable collections of type BasicGeopositions in my viewmodel. If yes then how?
Data to be plotted using polyline:
is a list of BasicGeoposition that contains latitudes and longitudes of all the points I need to connect. I tried this way <Maps:MapPolyline Path="{Binding Trip.PTSPositions}"/>
but it didn't work. PTSPositions is a list of BasicGeoposition.
What i want to perform:
I want to
MapPolyline polyLine = new MapPolyline() { StrokeColor = Colors.Blue, StrokeThickness = 5 };
polyLine.Path = new Geopath(Trip.PTSPositions);
MyMap.MapElements.Add(polyLine);
perform the above code behind code in XAML using MVVM where the Trip.PTSPositions
would be fetched dynamically and the map polyline would be drawn using data binding.
I searched online a lot. I couldn't find anything that does not use code behind for polyline
Here is the implementation suggested up in the comments.
This is the attached bindable property implementation for MapControl and it stays in the Widows Phone 8.1 project:
public class Polyline
{
public static readonly DependencyProperty PathProperty =
DependencyProperty.RegisterAttached(
"Path",
typeof(IBasicGeoposition[]),
typeof(Polyline),
new PropertyMetadata(null, OnPathChanged));
public static void SetPath(UIElement element, IBasicGeoposition[] value)
{
element.SetValue(PathProperty, value);
}
public static IBasicGeoposition[] GetPath(UIElement element)
{
return (IBasicGeoposition[]) element.GetValue(PathProperty);
}
private static void OnPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var mapControl = d as MapControl;
if (mapControl == null)
{
throw new InvalidOperationException(
"Polyline.Track property can only be attached to a MapControl!");
}
mapControl.MapElements.Clear();
mapControl.MapElements.Add(CreateMapPolyline(GetPath(mapControl)));
}
private static MapPolyline CreateMapPolyline(IEnumerable<IBasicGeoposition> track)
{
return new MapPolyline
{
Path = new Geopath(track.Select(x =>
new BasicGeoposition
{
Altitude = x.Altitude,
Latitude = x.Latitude,
Longitude = x.Longitude,
})),
StrokeColor = Colors.Red,
StrokeThickness = 3,
StrokeDashed = false
};
}
}
This interface stays in the PCL, probably close to it's implementation (you'll have to add your custom class implementing the interface):
public interface IBasicGeoposition
{
double Altitude { get; set; }
double Latitude { get; set; }
double Longitude { get; set; }
}
Than in view model you have Trip.PTSPositions
which is an array of IBasicGeoposition
. And in the view (XAML), you'll have:
<maps:MapControl attached:Polyline.Path="{Binding Trip.PTSPositions}"/>