Search code examples
xamlbing-mapsuwp-xamluwp-maps

Map Polyline on Bing Map Control


I am working on a UWP navigation app.

What I want to do?

  1. I want to draw multiple (10 to be exact) polylines on the Map control.
  2. I want one to be different color, while the others are grey.
  3. Once either of the polyline is selected the new selected polyline becomes of the primary color while the others are greyed out. Something like the Maps app for multiple routes just on a larger scale that shows movements of shipping trucks.

Everywhere online there are ways to implement the polyline via c# or code behind, but I want to do it via XAML as adding 10 polylines from codebehind doesn't give much flexibility with events and opacity and Tags and Names.

What all have I tried:

I tried creating an attached polyline to the mapElement but the issue with the approach is that I'll have to each time remove and recreate the polyline to change colors. More about this here. Also, it's just a pretty way of implementing polyline from code behind.

What am I doing currently:

I added the DataTemplate of the PolyLine in my Page.Resources like below:

 <DataTemplate x:Key="PolylineDataTemplate" x:DataType="polyLineData:IPolylinePath">
        <Polyline Points="{x:Bind Polyline,Mode=OneWay}" Fill="{x:Bind PolylineColor,Mode=OneWay}" Tag="{x:Bind PolylineTag,Mode=OneWay}" StrokeThickness="{x:Bind PolylineThinkness}" />
    </DataTemplate>`

Where the IPolylinePath is defined as:

public interface IPolylinePath
{
    SolidColorBrush PolylineColor { get; set; }

    int PolylineThinkness { get; set; }

    string PolylineTag { get; set; }

    IEnumerable<IBasicGeoposition> PolylinePoints { get; set; }

    Geopath PolylineGeopath { get; }

    PointCollection Polyline { get; }
}`

My Polyline property is populated as below:

 public PointCollection Polyline
    {
        get
        {
            PointCollection returnObject = new PointCollection();
            //could have used LINQ but wanted to check if the collection is being populated correctly
            foreach (var location in PolylinePoints)
            {
                returnObject.Add(new Windows.Foundation.Point(location.Latitude, location.Longitude));
            }
            return returnObject;
        }
    }

And I am just calling it in the MapItems control like below:

<maps:MapControl x:Name="MyMap"  >
                <maps:MapItemsControl ItemTemplate="{StaticResource PolylineDataTemplate}" ItemsSource="{x:Bind ViewModel.PolylinePoints}"/>
            </maps:MapControl>

The Issue is:

The code works perfectly well. Just the polyline is not visible. I thought that it's just small that's why I can't see it. So I increased the size and the distance and it just appears as a small arc on the top left corner (with some spacing) and doesn't get scoped or panned.

Can anyone please help?


Solution

  • Just the polyline is not visible.

    Firstly, it seems like you didn't give a Stoke property for the Polyline, by default it is null. Your code snippet set color with Fill property it is not for the color of the line, you may find the value of StrokeThickness has no influence with the Polyline and a straight line will not been seen without the Stroke property. So here the color should be bind to Stroke property.

    it just appears as a small arc on the top left corner

    It is because you build points of the Points property for the Polyline by code line new Windows.Foundation.Point(location.Latitude, location.Longitude). The latitude and longitude defined the element location on the MapControl not the application view. In another words, actually you add a GeoPoint to the PointCollection, not a Point. So you may need to transfer the GeoPoint to Point by GetOffsetFromLocation(Geopoint, Point) method.

    doesn't get scoped or panned.

    For this, the Polyline is actually a shape not a MapElement. You should control its MapLocation by listening the map zoom events. If you want it be pan with the map, you should use Map​Polyline. For sample of this please reference the scenario 2 of the official sample. But MapPolyline cannot be added directly by binding, only code behind.

    A completed simple sample based on yours for testing as follows:

    XAML

    <Page.Resources>
       <DataTemplate x:Key="PolylineDataTemplate" x:DataType="local:PolylinePath">
           <Polyline
               Points="{x:Bind Polyline}"
               Stroke="{x:Bind PolylineColor}"
               StrokeThickness="{x:Bind PolylineThinkness}"
               Tag="{x:Bind PolylineTag}" />
       </DataTemplate>
    </Page.Resources>
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
       <maps:MapControl x:Name="MyMap" Loaded="MyMap_Loaded">
           <maps:MapItemsControl x:Name="mapitems" ItemTemplate="{StaticResource PolylineDataTemplate}" />
       </maps:MapControl>
       <Button
           x:Name="btnaddpolyline"
           Click="btnaddpolyline_Click"
           Content="add" />
    </Grid>
    

    Code behind:

    public sealed partial class MainPage : Page
    {
        public List<PolylinePath> polylines { get; set; }
        Geopoint SeattleGeopoint = new Geopoint(new BasicGeoposition() { Latitude = 47.604, Longitude = -122.329 });       
        public MainPage()
        {
            this.InitializeComponent();
        }
        private void MyMap_Loaded(object sender, RoutedEventArgs e)
        {
            MyMap.Center = SeattleGeopoint;
            MyMap.ZoomLevel = 16;
        }
        private void btnaddpolyline_Click(object sender, RoutedEventArgs e)
        {
            polylines = new List<PolylinePath>()
            {
                new PolylinePath(MyMap)
                {
                    PolylineColor=new SolidColorBrush(Colors.Red),
                    PolylineThinkness=3,
                    PolylineTag="testing",
                    PolylinePoints = new List<BasicGeoposition>()
                    {
                        SeattleGeopoint.Position,
                        new BasicGeoposition()
                        {
                            Latitude = SeattleGeopoint.Position.Latitude + 0.003,
                            Longitude = SeattleGeopoint.Position.Longitude - 0.003
                        }
                    }
                }
            };
            mapitems.ItemsSource = polylines;
        }
    }
    public class PolylinePath
    {
        public PolylinePath(MapControl MyMap)
        {
            this.MyMap = MyMap;
        }
        MapControl MyMap;
        public SolidColorBrush PolylineColor { get; set; }
    
        public int PolylineThinkness { get; set; }
    
        public string PolylineTag { get; set; }
    
        public IEnumerable<BasicGeoposition> PolylinePoints { get; set; }
    
        public PointCollection Polyline
        {
            get
            {
                PointCollection returnObject = new PointCollection();
                //could have used LINQ but wanted to check if the collection is being populated correctly
                foreach (var location in PolylinePoints)
                {
                    Point actualpoint;
                    MyMap.GetOffsetFromLocation(new Geopoint(location), out actualpoint);
                    returnObject.Add(actualpoint);
                }
                return returnObject;
            }
        }
    }