0

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

Community
  • 1
  • 1
iam.Carrot
  • 4,976
  • 2
  • 24
  • 71
  • @Clemens I can't seem to understand how to bind it. Do you have a sample I could take a look at. I have edited the question with the data I have to plot using a polyline – iam.Carrot Nov 16 '16 at 12:54
  • Make a bindable attached property that can bind to your PTSPositions and create, add and remove MapElements from the MapControl – atomaras Nov 18 '16 at 03:16
  • @atomaras , thank you, the issue with that approach is that I am using a common portable Library project as for my viewModels and thus I can't use the Geopoint as the data type. And if I create the property in the view's code behind, my xaml would not use it as the data context of the view is set to the viewModel in the common Portable library project. – iam.Carrot Nov 18 '16 at 03:23
  • That's fine. Make a model class inside your PCL to represent a Geopoint and convert it inside the attached property to the actual Geopoint used by the MapControl. – atomaras Nov 18 '16 at 16:32

1 Answers1

1

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}"/>
cosmo
  • 187
  • 2
  • 11
  • I am sorry it took me so long to implement the solution. It works perfectly as desired. thanks for all the help. I just have one query, what if I want to add multiple polylines to my map? For eg: having 3 polyline each of different colour for 3 different road ways to reach from start point to end point. Can you please help me with adding multiple polylines to my MapControl? I've upvoted your answer, I shall accept it as soon as you respond to this comment. Thank you again cheers mate – iam.Carrot Mar 14 '17 at 14:07
  • Could you please edit your answer to the way you're referring to? It'll be of great help – iam.Carrot Mar 14 '17 at 15:14
  • Create a new attached property class with a dependency property Paths of type ObservableCollection. IPolylinePath will have 2 properties Color of type Color and Positions of type IEnumerable. You'll have to implement it. In OnPathsChanged loop on the items of Paths and for each create and add a MapPolyline to the MapElements list as it was done previously. You'll have to subscribe to Paths.CollectionChanged. Implement OnPathsCollectionChanged, this is tricky since you have to either clear/ recreate all MapElements or you'll have to add/remove paths. – cosmo Mar 14 '17 at 15:30
  • Great! Thank you. Cheers mate. I'll try it out. Shall comment.if I get stuck, I don't think I would though. – iam.Carrot Mar 14 '17 at 15:33