This project has moved. For the latest updates, please go here.

Multiple Layers

Feb 15, 2016 at 2:26 PM
Hi, great control by the way.

I need to add multiple layers to my map so was going down the route of creating an observable collection of TileLayers and then binding that collection in the map control....

TileLayers={Binding MyTileLayerCollection}

Unfortunately the maps do not render when I do this.

If I create them in the code behind i.e

dim layer1 as new tilelayer
dim layer2 as new tilelayer

Mapcontrol.add(layer1)
Mapcontrol.add(layer2)

The maps render fine?
What is the difference between the two methods apart from the obvious - I need to use the prior method as I am all Mvvm?

Any help much appreciated.
Coordinator
Feb 15, 2016 at 4:53 PM
Edited Feb 15, 2016 at 4:53 PM
Works for me. Did you set the DataContext of the Map control (or its parent Panel or Window) to an instance of your view model?
Feb 16, 2016 at 9:49 AM
Hi,
Thanks for getting back to me. The datacontext is fine as its servicing other bindings. I am using MVVMLight in a WinRT store app.

Here is some code to show whats happening. If you uncomment the second map control the single layer renders - but if you use the first map control which is bound to the collection with the same one layer in it it does not render.

App.Xaml
<Application
    x:Class="XamlMapTest.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     d1p1:Ignorable="d" 
    xmlns:d1p1="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="using:XamlMapTest">

    <Application.Resources>
        <local:ViewModelLocator x:Key="Locator" d:IsDataSource="True"/>
    </Application.Resources>
</Application>
ViewModelLocator
Imports GalaSoft.MvvmLight.Ioc
Imports Microsoft.Practices.ServiceLocation
Imports GalaSoft.MvvmLight.Views

''' <summary>
''' This class contains static references to all the view models in the
''' application and provides an entry point for the bindings.
''' It also initialises the navigation IOC 
''' </summary>
Public Class ViewModelLocator
    ''' <summary>
    ''' Initializes a new instance of the ViewModelLocator class.
    ''' </summary>
    Public Sub New()

        ServiceLocator.SetLocatorProvider(Function() SimpleIoc.[Default])

        'Register ALL View Models to the IOC container
        'Standard View Models
        SimpleIoc.[Default].Register(Of ViewModel_VM)()

    End Sub

#Region "View Based View Models"
    Public ReadOnly Property ViewModel() As ViewModel_VM
        Get
            Return ServiceLocator.Current.GetInstance(Of ViewModel_VM)()
        End Get
    End Property
#End Region
ViewModel_VM
Imports GalaSoft.MvvmLight

Public Class ViewModel_VM
    Inherits ViewModelBase

    Private m_tilelayercollection As ObservableCollection(Of MapControl.TileLayer)
    Private m_tile_layer As MapControl.TileLayer

    Public Sub New()

        'Add a layer

        Dim tlc As New ObservableCollection(Of MapControl.TileLayer)
        Dim tl As MapControl.TileLayer
        Dim ts As MapControl.TileSource

        tl = New MapControl.TileLayer
        tl.SourceName = "A"
        tl.Description = "Description"
        tl.MinZoomLevel = 2
        tl.MaxZoomLevel = 10
        ts = New MapControl.TileSource
        ts.UriFormat = "http://{c}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        tl.TileSource = ts

        tile_layer = tl

        tlc.Add(tl)

        tilelayercollection = tlc

    End Sub

    Public Property tilelayercollection As ObservableCollection(Of MapControl.TileLayer)
        Get
            Return m_tilelayercollection
        End Get
        Set
            m_tilelayercollection = Value
            RaisePropertyChanged()
        End Set
    End Property

    Public Property tile_layer As MapControl.TileLayer
        Get
            Return m_tile_layer
        End Get
        Set
            m_tile_layer = Value
            RaisePropertyChanged()
        End Set
    End Property

End Class
XamlMapTest.MainPage
<Page
    x:Class="XamlMapTest.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:XamlMapTest"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:Map="using:MapControl"
    mc:Ignorable="d">

    <Page.DataContext>
        <Binding Path="ViewModel" Source="{StaticResource Locator}"/>
    </Page.DataContext>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
        <Map:Map  ZoomLevel="5" TileLayers="{Binding tilelayercollection}"/>
        <!--<Map:Map  ZoomLevel="5" TileLayer="{Binding tile_layer}"/>-->
    </Grid>
</Page>
Feb 16, 2016 at 10:32 AM
I can get around it by adding all the layers as Static Resources and then setting the visibility of each layer as I need it. Just not the right way to do it as the collection is perfect if I can get it working....
Coordinator
Feb 16, 2016 at 4:11 PM
Edited Feb 16, 2016 at 5:35 PM
Not sure what's wrong with your code (and I don't like VB), but this simple UWP example works for me:
<Page ...>
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <map:Map ZoomLevel="5"  TileLayers="{Binding TileLayers}" />
        <Button HorizontalAlignment="Right" VerticalAlignment="Bottom"
                Content="Add Layer" Click="AddLayerButtonClick"/>
    </Grid>
</Page>
Code behind:
public sealed partial class MainPage : Page
{
    private TileLayer tl1 = new TileLayer
    {
        TileSource = new TileSource { UriFormat = "http://{c}.tile.openstreetmap.org/{z}/{x}/{y}.png" }
    };

    private TileLayer tl2 = new TileLayer
    {
        TileSource = new TileSource { UriFormat = "http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png" }
    };

    public MainPage()
    {
        this.InitializeComponent();
        DataContext = new ViewModel();
    }

    private void AddLayerButtonClick(object sender, RoutedEventArgs e)
    {
        var vm = (ViewModel)DataContext;

        switch (vm.TileLayers.Count)
        {
            case 0:
                vm.TileLayers.Add(tl1);
                break;
            case 1:
                vm.TileLayers.Add(tl2);
                break;
            default:
                vm.TileLayers.Clear();
                break;
        }
    }
}

public class ViewModel
{
    public ObservableCollection<TileLayer> TileLayers { get; private set; }
        = new ObservableCollection<TileLayer>();
}