Add custom tiles to map in Xamarin Forms

If we want to use other maps than the platforms default in our apps we need to provide tiles to the map view. To do that we need to create a custom renderer per platform.

iOS
In iOS we need to create an url template that contains {x}, {y} and {z}. Those be replaced with values from the map engine.

protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
    if(e.NewElement != null)
    {
        var map = (MKMapView)Control;
 
        var urlTemplate = "https://urltomaptiles/{x}/{y}/{z}";
        var tileOverlay = new MKTileOverlay(urlTemplate);
 
        map.OverlayRenderer = OverlayRenderer;
 
        map.AddOverlay(tileOverlay);
    }
}
private MKOverlayRenderer RenderOverlay(MKMapView mapView, IMKOverlay overlay)
{
    var tileOverlay = overlay as MKTileOverlay;
 
    if(tileOverlay != null)
    {
         return new MKTileOverlayRenderer(tileOverlay);
    }
 
    return new MKOverlayRenderer(overlay);
}

If we are getting tiles from a service that not supporting the url format with x-,y- and z value we can customize the url. To do that we need to subclass MKTileOverlay and override the URLForTilePath method. In that method we will write the code that created the url. I recommend to create a helper class for that so we can reuse it on the other platforms.

public class CustomTileOverlay : MKTileOverlay
{
     public override void LoadTileAtPath(MKTileOverlayPath path, MKTileOverlayLoadTileCompletionHandler result)
     {
         base.LoadTileAtPath(path, result);
     }
 
     public override NSUrl URLForTilePath(MKTileOverlayPath path)
     {
         //Here we write the code for creating the url.
         var url = MapHelper.CreateTileUrl((int)path.X, (int)path.Y, (int)path.Z);
 
         return new NSUrl(url);
     }
}

Instead of creating a MKTileOverlay we will create a CustomTileOverlay and add it to the map.

map.AddOverlay(new CustomTileOverlay());

Android
Except to subclass MapRenderer we also need to implement the IOnMapReadyCallback interface. The method OnMapReady will handle when the GoogleMap object is ready so we can work with it. But first we need to request the GoogleMap object in the override of the OnElementChanged method.

public class ExtendedMapRenderer : MapRenderer, IOnMapReadyCallback
{
    protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e)
    {
        base.OnElementChanged(e);
 
        if(e.NewElement != null)
        {
            ((MapView)Control).GetMapAsync(this);    
        }
    }
 
    public void OnMapReady(GoogleMap googleMap)
    { 
        var options = new TileOverlayOptions();
        options.InvokeTileProvider(new CustomTileProvider());
        googleMap.AddTileOverlay(options);
    }
}

In Android we always need to create an own tile provider.

public class CustomTileProvider : UrlTileProvider
{
    public CustomTileProvider() : base(256,256) {}
 
    public override URL GetTileUrl(int x, int y, int zoom)
    {
        //Here we write the code for creating the url.
        var url = MapHelper.CreateTileUrl(x, y, zoom);
 
        return new URL(url);
    }
}

UWP (Windows 10)
As in iOS, UWP using an url that contains {x},{y} and {z} that will be replaced by the map engine.

protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
{
    base.OnElementChanged(e);
 
    if (e.NewElement != null)
    {
        map = Control as MapControl;
 
        HttpMapTileDataSource dataSource = new HttpMapTileDataSource("https://urltomaptiles/{x}/{y}/{z}");      
        MapTileSource tileSource = new MapTileSource(dataSource);
        map.TileSources.Add(tileSource);
 
     }
}

If we want to modify the url we using the UriRequested event on HttpMapTileDataSource.

HttpMapTileDataSource dataSource = new HttpMapTileDataSource();
dataSource.UriRequested += DataSource_UriRequested;

The code for modifying the url is placed in the event handler.

private void DataSource_UriRequested(HttpMapTileDataSource sender, MapTileUriRequestedEventArgs args)
{
    var deferral = args.Request.GetDeferral();
 
    //Here we write the code for creating the url.
    var url = MapHelper.CreateTileUrl(args.X, args.Y, args.ZoomLevel);
    args.Request.Uri = new Uri(url);
 
    deferral.Complete();
}

Using the symbol enumeration for icons/symbols in Windows 10 universal app

If you are developer and not a graphic artist it is always a challange to find/create icons. Windows 10 has a symbol enumeration that you can use that contains the most common icons/symbols (you find the complete list of symbols here: https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.controls.symbol.aspx).

The not only look good they are easy to use to, just use the SymbolIcon element. The code below shows a settings icon.

<SymbolIcon Symbol="Setting" />

If you want to change color on the icon just use the Foreground attribute.

<SymbolIcon Foreground="Gold" Symbol="Favorite" />

The symbols is based on the “Segoe MDL2 Assets” font (You can read more about it here: https://msdn.microsoft.com/en-us/library/windows/apps/jj841126.aspx).

Symbols in a Windows 10 app

Symbols in a Windows 10 app

If you want to read more about Windows 10 development I have created a list with all my Windows 10 blog posts, http://danielhindrikes.se/windows-10/, more will be added.

Pivot in Windows 10 universal apps

If you are a Windows Phone developer I guess you are familiar with the Pivot control. In Windows 10 the pivot control has taken the step into desktop apps.

Pivot is a easy way to navigate between pages in your app. To navigate to an other page in the control just click the header or swipe left or right.
 

Pivot

Pivot in a desktop app

Pivot

Pivot on phone app




The pivot control is easy to implement, for every page you want to add to the Pivot control you just add a PivotItem as in the code below.

<Pivot Title="Pivot sample">
            <Pivot.Items>
                <PivotItem Header="Pivot 1">
                    <Grid>
                        <TextBlock Text="Content of pivot 1" />
                    </Grid>
                </PivotItem>
                <PivotItem Header="Pivot 2">
                    <views:MyView />
                <PivotItem Header="Pivot 3">
                    <Grid>
                        <TextBlock Text="Content of pivot 3" />
                    </Grid>
                </PivotItem>
            </Pivot.Items>
        </Pivot>

Customize the Pivot
Customizations of Pivot is done with DataTemplates. The Pivot control has a property called TitleTemplete for the template for the title of the pivot and a property called HeaderTemplate for the headers of the pivot items. Templates can be defined in resources for the page or for the application (in App.xaml). The template can only have one child element, but it could be for example a StackPanel or a Grid if you want to add more than text in your headers. For example if you will have ha more tab like experience with icons and text as you may have seen in some apps.

<Page.Resources>
        <DataTemplate x:Key="PivotHeader">
                <TextBlock FontSize="18" Foreground="Blue" Text="{Binding}" />
        </DataTemplate>
</Page.Resources>

Next step is to set the new template to the Pivot.

 <Pivot HeaderTemplate="{StaticResource PivotHeader}" Title="Pivot sample">

You can also define a style in App.xaml if you want it to be on all Pivots in the app.

 <Application.Resources>
        <Style TargetType="Pivot">
            <Setter Property="HeaderTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <Grid>
                            <TextBlock FontSize="18" Foreground="Blue" Text="{Binding}" />
                        </Grid>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>
 
The code examples above is for PivotItem headers, if you want it to be for the Pivot title, just change HeaderTemplate to TitleTimplate.
</Application.Resources>

The complete code can be found on GitHub, https://github.com/dhindrik/windows10samples

If you want to read more about Windows 10 development I have created a list with all my Windows 10 blog posts, http://danielhindrikes.se/windows-10/, more will be added.

SplitView in Windows 10 universal app

One of the new controls in the SDK for Windows 10 universal apps is the SplitView control. I guess you have seen the apps with the hamburger menu. If you want to create an app with a hamburger menu I recommend you to use SplitView.


SplitView

The control is splitting the views/pages in two parts, the left one is called Pane and can be used for menus, for example. The Pane has for different display modes.

Overlay
When the pane is open it will be shown over the main content of the page.

CompactOverlay
Is shown the same way as overlay, but with thinner. I recommend yo just show icons in this mode.

Inline
When the pane is open it will be beside the main content, see the screenshot above.

CompactInline
Inline also has a compact mode as with the CompactOverlay I recommend you to just use icons when showing the pane in CompactInline

<SplitView Name="Split" OpenPaneLength="200" IsPaneOpen="False" DisplayMode="Overlay">
            <SplitView.Pane>
                <StackPanel Padding="10">
                    <TextBlock Text="Item 1" />
                    <TextBlock Margin="0,10" Text="Item 2" />
                    <TextBlock Text="Item 3" />
                    <TextBlock Margin="0,10" Text="Item 4" />
                </StackPanel>
            </SplitView.Pane>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="50" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <Button Background="White" Click="Button_Click">
                    <StackPanel>
                        <Rectangle Height="3" Width="20" Fill="Black" />
                        <Rectangle Margin="0,5" Height="3" Width="20" Fill="Black" />
                        <Rectangle Height="3" Width="20" Fill="Black" />
                    </StackPanel>
                </Button>
 
                <TextBlock Margin="10" Grid.Row="1" Text="Main content here" />
 
            </Grid>
        </SplitView>

The default placement of the pane is to left, but you can also have it on the right side. Just set the PanePlacement property to right.

 <SplitView Name="Split" PanePlacement="Right" OpenPaneLength="200" IsPaneOpen="False" DisplayMode="Inline">

The complete code can be found on GitHub, https://github.com/dhindrik/windows10samples

If you want to read more about Windows 10 development I have created a list with all my Windows 10 blog posts, http://danielhindrikes.se/windows-10/, more will be added.

Using compiled bindings in your Windows 10 universal app

One of the news in the Windows 10 SDK is that you can use compiled binding. In pre Windows 10 bindings was created in run time. When you’re building your windows universal app for windows 10 you can created bindings in compile time. This to boost the performance of the bindings, compiled bindings will make the page load much faster. This blog post will introduce you with the basics of compiled bindings.

To create a binding that will be created in compile time you will use x:Bind instead of Binding to create the binding.

      <TextBlock Text="{x:Bind Title}" />

One big difference against is that the binding will not be to DataContext, it will be to the page. If the code above should work you have to create a Title property in the code behind file. If you don’t do that you will get a error when you compiling your app. The reason to to bind to the actuall page instead of DataContext is that DataContext is of type object and the compiler will not know what you will assign to it during run time. Because you binding to the actual page it is also possible to bind directly to other controls on your page.

If you using a binding in a data template you have to specify data type for the data template with x:DataType as in the code below. Don’t forget to declare the namespace for your data type. In this example I have created a property in my code behind file called ViewModel that has a Items property that I binding to the ItemsSource of the ListView.

<ListView ItemsSource="{x:Bind ViewModel.Items}">  
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="model:ItemModel">
                        <TextBlock Text="{x:Bind Title}" />
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

The code behind can looks like the code below. In this example DataContext is set when the view is created and the ViewModel will have a method for loading data.

public sealed partial class ItemsView
{
        protected ItemsViewModel ViewModel { get { return DataContext as ItemsViewModel; } }
 
        public ItemsView()
        {
            this.InitializeComponent();
            DataContextChanged += ItemsView_DataContextChanged;
        }
 
        private async void ItemsView_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
        {
            if(ViewModel != null)
            {
                await ViewModel.LoadData();
            }
        }
}