Xamarin Forms Flow Layout

Xamarin Forms is missing a flow layout control so I made one! It’s available here. It lays out child views from right to left, and moves on to a new row when it runs out of space.

Here’s a screenshot of a demo app…

Screen Shot 2017-03-22 at 20.45.36

This is the first layout I’ve made and I was surprised how easy it was. Layouts are written in the cross platform code; there isn’t a platform specific element.

To create a layout you create a new class that inherits from Layout…

public class FlowLayout : Layout<View>

The override the LayoutChildren and OnMeasure methods…

protected override void LayoutChildren(double x, double y, double width, double height)
{
    var layoutInfo = new LayoutInfo(Spacing);
    layoutInfo.ProcessLayout(Children, width);

    for (int i = 0; i < layoutInfo.Bounds.Count; i++)
    {
        if (!Children[i].IsVisible)
        {
            continue;
        }

        var bounds = layoutInfo.Bounds[i];
        bounds.Left += x;
        bounds.Top += y;

        LayoutChildIntoBoundingRegion(Children[i], bounds);
    }
}
protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
{
    var layoutInfo = new LayoutInfo(Spacing);
    layoutInfo.ProcessLayout(Children, widthConstraint);
    return new SizeRequest(new Size(widthConstraint, layoutInfo.HeightRequest));
}

I chose to use another class – LayoutInfo – to handle the layout. This meant I was able to easily write unit tests. Trying to unit test the actual layout class is difficult as it needs the Xamarin Forms framework to work in the test environment.

 

Xamarin Forms Flow Layout

Xamarin Cross Platform Version Numbers

In this post I discuss a solution for creating a consistent version number across .net, Android, and iOS for Xamarin cross platform apps. I also list a couple of powershell scripts which help with setting the versions

The Problem

.net, Android, and iOS, all use different systems for versioning. When developing cross platform apps we consistency of numbering across the different platforms.

.net Version Numbers

.net Version numbers use a four part version number with the format <major version>.<minor version>.<build number>.<revision>

Often you’ll see version numbers with asterisks – 1.0.* or 1.0.. – When these are used the build number the build number increments every day and the revision number is random. .net version numbers are stored in the AssemblyInfo file for a project.

Android Version Numbers

Two numbers are used in Android versioning – the versionCode is an integer with higher numbers indicating more recent versions. It’s never shown to users. The versionName is a string which is displayed to users and can be anything you want. These numbers are stored in the AndroidManifest.xml file.

iOS Version Numbers

An iOS app has two version numbers which work together – A Version Number (CFBundleShotVersionString) and a Build Number (CFBundleVersion). The Version number identifies a release, and for each release the build number increments for each build that is submitted to the store. These numbers are stored in the Info.plist file.

‘Common’ Version Numbers

For Xamarin applications we want consistency of version numbers across the platform specific versions of an app, and it makes sense to use the .net version number as the ‘master’.

We can either use the automatic numbers as described above, or, if using TFS/VSTS use a number in a format such as 1.2.$(DayOfYear)$(Rev:.rr) and update the assemblyinfo

For example lets say the .net version number is 1.4.102.13.

This powershell script will update all the assemblyinfo files in a solution.

[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string] $version,
[Parameter(Mandatory=$true)]
[string] $path
)

Cls

Write-Output &quot;Version Assembly Infos&quot;
Write-Output &quot;Version: $version&quot;

$newVersion = &quot;[assembly: AssemblyVersion(&quot;&quot;$version&quot;&quot;)]&quot;
$newFileVersion = &quot;[assembly: AssemblyFileVersion(&quot;&quot;$version&quot;&quot;)]&quot;

$files = Get-ChildItem -Path $path -Filter &quot;AssemblyInfo.cs&quot; -Recurse

foreach($file in $files)
{
(Get-Content $file.FullName) `
-replace '\[assembly: AssemblyVersion\(&quot;(.*)&quot;\)\]', $newVersion `
-replace '\[assembly: AssemblyFileVersion\(&quot;(.*)&quot;\)\]', $newFileversion |
Out-File $file.FullName
}

For Android the versionName, which is just for display, can be set to the full four part version number from .net. The versionCode just needs to increase from the previous version. Here's a script which takes the global build number from TFS, but could be easily modified to increment the existing number.

With the example version number this would give us a versionName – 1.4.102.13 – and a versionCode which is unique incremented number.

[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string] $version,

[Parameter(Mandatory=$true)]
[string] $manifestPath
)

# Sets version in an Android manifest.
# The version name is set to the specified value.
# The version code is set to the build number from TFS.

Write-Output &quot;Setting Android Version&quot;
Write-Output &quot;Version: $version&quot;
Write-Output &quot;Manifest: $manifestPath&quot;

$xml = [xml](Get-Content $manifestPath)
$manifestNode = $xml.manifest

$versionCodeNew = $env:BUILD_BUILDID # This is the global build number from tfs - it increments with every build of every project.

$manifestNode.Attributes[&quot;android:versionCode&quot;].Value = $versionCodeNew
$manifestNode.Attributes[&quot;android:versionName&quot;].Value = $version

$xml.Save($manifestPath)

Write-Output &quot;Manifest Updated&quot;

For iOS we can split the four part version number. The first three parts can be used for the version number and the last part can be used for the build number. Here's a script for that. From the example version number this gives us a version number – 1.4.102 – and a build number – 13.

[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string] $version,

[Parameter(Mandatory=$true)]
[string] $infoPath
)

cls

Write-Output &quot;Version: $version&quot;
Write-Output &quot;InfoPath: $infoPath&quot;

$elements = $version.Split(&quot;.&quot;)
$major = $elements[0]
$minor = $elements[1]
$revision = $elements[2]
$build = $elements[3]

$iosVersion = &quot;$major.$minor.$revision&quot;

$xml = [xml](Get-Content $infoPath)

$buildNode = $xml.SelectSingleNode(&quot;.//key[text()=&quot;&quot;CFBundleVersion&quot;&quot;]&quot;)
$buildNode.NextSibling.InnerText = $build

$versionNode = $xml.SelectSingleNode(&quot;.//key[text()=&quot;&quot;CFBundleShortVersionString&quot;&quot;]&quot;)
$versionNode.NextSibling.InnerText = $iosVersion

$xml.Save($infoPath)
Xamarin Cross Platform Version Numbers

TFS Mac Build Agent – The type initializer for ‘System.Net.Http.CurlHandler’ threw an exception. Failed to connect.

I’ve just spent a couple of hours on this error which occurs when setting up a Mac TFS build agent on OSX El Capitan.

There are a lot of solutions out there but the one that worked for me came from the [.net core setup instructions] (https://www.microsoft.com/net/core#macos).

Simply run the following commands…

brew update
brew install openssl
mkdir -p /usr/local/lib
ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/
ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/

… then install the agent again…

~/myagent$ ./config.sh

Hopefully this will save you some time and frustration 🙂

TFS Mac Build Agent – The type initializer for ‘System.Net.Http.CurlHandler’ threw an exception. Failed to connect.

Xamarin Forms – Xaml Resource Dictionaries

This post shows how to create a standalone XAML resource dictionary for use in Xamarin Forms. Normally resource dictionaries live in the xaml for an Application or a VisualElement, putting them in a standalone class makes it easy to share them across applications.

To create the dictionary:

  • Add a new xaml page to your project.
  • In xaml change root element to ResourceDictionary from Page.
  • In code change the class so it doesn’t inherit from Page.

Here are examples of the xaml and code files:

<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Microlise.Mobile.UI.Demo.OtherStyle">
<Style x:Key="ButtonPrimary" TargetType="Button">
<Setter Property="BackgroundColor" Value="#9D6381" />
<Setter Property="TextColor" Value="#242728" />
<Setter Property="FontAttributes" Value="Bold" />
</Style>
</ResourceDictionary>
using System;

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace Microlise.Mobile.UI.Demo
{
public partial class OtherStyle
{
public OtherStyle()
{
this.InitializeComponent();
}
}
}
Xamarin Forms – Xaml Resource Dictionaries

Tracking Custom Events with Xamarin, HockeyApp, and Azure Application Insights

This post shows how to log and report on custom events in Xamarin apps. There are a few steps needed to accomplish this:

  • Integrate HockeyApp into your app.
  • Record the events
  • Configure Applications Insights
  • Analyse the data

Integrate HockeyApp

HockeyApp have a guide for this here.

Record Metrics

To create some data for this post I made a little demo app – the source is available at GitHub

sshot-1

You use the MetricsManager.TrackEvent method to send the events to HockeyApp. It batches events and sends them every 15 seconds, or once 50 events are in the batch. You can call it without arguments…

MetricsManager.TrackEvent("Show Page - Page 1");

… or with custom properties…

MetricsManager.TrackEvent("DurationEvent", new Dictionary<string, string> { { "property", "value" } }, new Dictionary<string, double> { { "duration", duration} });

Once set up correctly you’ll see the events appearing in HockeyApp…

screen-shot-2017-02-19-at-16-23-03

Setup Application Insights

The process of linking HockeyApp to Application Insights is described here. The key steps are…

  • Create an API token in HockeyApp. This is under your User Profile, not against the App.
  • In Azure create a new entry in Application Insights. The application type is HockeyApp Bridge Application and the HockeyApp token is the API token you created, not the app’s id.
  • Wait for data to appear. In my experience the no data message was displayed even after events were coming through, so it pays to run some queries to check.

Analyse Data

Once the data is appearing in Insights it’s time to analyse. To do this we need to use it’s special query language. A reference is available but lets look at some examples…

How many times has a page been viewed?

customEvents
| where name startswith "Show Page"
| summarize count() by name

screen-shot-2017-02-20-at-08-23-39

Can we show that data in a pie chart?

customEvents
| where name startswith "Show Page"
| summarize count() by name
| render piechart

screen-shot-2017-02-20-at-08-17-21

What are the minimum, maximum, and average durations of my click events?

customEvents
| where name == "DurationEvent"
| extend Duration = todouble(customMeasurements.duration)
| summarize min(Duration), max(Duration), avg(Duration)

screen-shot-2017-02-20-at-08-30-21

When do most click events occur?

customEvents
| where name == "DurationEvent"
| extend Duration = todouble(customMeasurements.duration)
| summarize Count = count() by Hour = datepart("hour", timestamp)
| render barchart
Tracking Custom Events with Xamarin, HockeyApp, and Azure Application Insights

Xamarin Forms – Binding List Item Commands to the Parent ViewModel

This post shows how to bind a list item command to the parent list views binding context. Often you want to send the command to the view model, not the object that the list item is bound to.

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="App1.DemoPage">
   <ListView ItemsSource="{Binding Items}" x:Name="List">
      <ListView.ItemTemplate>
         <DataTemplate>
            <TextCell Text="{Binding}" Command="{Binding Path=BindingContext.ListItemCommand, Source={x:Reference Name=List}}" CommandParameter="{Binding}" />
         </DataTemplate>
      </ListView.ItemTemplate>
   </ListView>
</ContentPage>

To do it we have given the list view a name. Then in the item command binding we use that reference in the binding path. The command parameter is the list item’s binding context.

Xamarin Forms – Binding List Item Commands to the Parent ViewModel

Xamarin Forms Async Commands with Parameters

A quick mini post to show how to pass parameters to asynchronous commands in Xamarin Forms. I keep forgetting the syntax for this so it’s useful to have a reminder!

public class DemoViewModel
{
    public DemoViewModel()
    {
        this.DemoCommand = new Command<double>(async (x) => await CalculateSquareSlowly(x));
    }

    public ICommand DemoCommand { get; private set; }

    private async Task<double> CalculateSquareSlowly(double number)
    {
        await Task.Delay(2000);
        return number * number;
    }
}
Xamarin Forms Async Commands with Parameters