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

Android StartActivityForResult and Xamarin Forms

In this post I demonstrate a technique for using getting the results from Android activities in Xamarin Forms apps. The code for this example is available here.

The Problem

In a standard Android app you can use the StartActivityForResult method on your current activity to start a child activity. When the child activity completes the OnActivityResult is called on the parent activity.

In a Xamarin Forms app you don’t really have a parent activity – you have the Forms.Context object but if you use that all results will go to the main activity which is messy. If you are making a library you can’t even do that.

The Solution

The example app prompts the user to select a contact, then displays the name of the selected contact.

The magic takes place in the Phonebook class.

    public class Phonebook : IPhonebook
    {
        public Task&lt;string&gt; GetContactName()
        {
            var intent = new Intent(Forms.Context, typeof(PhonebookActivity));
            Forms.Context.StartActivity(intent);

            var tcs = new TaskCompletionSource&lt;string&gt;();
            EventHandler handler = null;

            handler = (sender, args) =&gt;
            {
                PhonebookActivity.ContactResultHandler -= handler;
                tcs.SetResult(((PhonebookActivity)sender).ContactName);
            };

            PhonebookActivity.ContactResultHandler += handler;

            return tcs.Task;
        }
    }

Although it’s short, its doing a fair bit of work. The GetContactName method starts starts the PhonebookActivity from the app’s main activity.It then uses a TaskCompletionSource to wait for an event from the PhoneBookActivity. It returns a Task so it can be called asynchronously.

There’s more magic in the PhonebookActivity class. The main reason for using this activity is to give us somewhere to call StartActivityForResult from. When the activity starts it creates and starts an Intent to prompt the user to select a contact. When that activity finishes it takes the result and raises an event back to the Phonebook class. The PhonebookActivity is never actually displayed on screen – really it’s just a wrapper for the select contact activity.

    [Activity(Label = "PhonebookActivity")]
    public class PhonebookActivity : Activity
    {
        private const int RequestCodeSelectContact = 1;

        public string ContactName { get; private set; }

        public static EventHandler ContactResultHandler;

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            if (bundle == null)
            {
                var intent = new Intent(Intent.ActionPick, ContactsContract.Contacts.ContentUri);

                if (intent.ResolveActivity(PackageManager) != null)
                {
                    StartActivityForResult(intent, RequestCodeSelectContact);
                }
            }
        }

        protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
        {
            ContactName = string.Empty;

            if (requestCode == RequestCodeSelectContact &amp;&amp; resultCode == Result.Ok)
            {
                var uri = data.Data;

                string[] projection = new string[] { ContactsContract.ContactNameColumns.DisplayNamePrimary };

                var cursor = ContentResolver.Query(uri, projection, null, null, null);

                if (cursor.MoveToFirst())
                {
                    int columnIndex = cursor.GetColumnIndexOrThrow(ContactsContract.ContactNameColumns.DisplayNamePrimary);
                    ContactName = cursor.GetString(columnIndex);
                }
            }

            ContactResultHandler?.Invoke(this, new EventArgs());
            Finish();
        }
    }
Android StartActivityForResult and Xamarin Forms

Creating Nuget Packages For Xamarin Forms

Here’s a quick post that describes how to create a nuget package that can be used across Xamarin Forms and platform specific projects. The goal is to create a nuget package that targets the appropriate platform for each project.

Prerequisites

You need nuget.exe available from here.

Nuget Package Explorer is useful to see what has been packaged. Get it here.

All commands should be run in a command prompt with the path to the nuget.exe in the path.

Creating the Package

First we have to create a .nuspec file…

nuget spec

This creates a file called ProjectName.nuspec

Intially the file looks like this:


<?xml version="1.0"?>
<package >
  <metadata>
    <id>$id$</id>
    <version>$version$</version>
    <title>$title$</title>
    <authors>$author$</authors>
    <owners>$author$</owners>
    <licenseUrl>http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE</licenseUrl>
    <projectUrl>http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE</projectUrl>
    <iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>$description$</description>
    <releaseNotes>Summary of changes made in this release of the package.</releaseNotes>
    <copyright>Copyright 2016</copyright>
    <tags>Tag1 Tag2</tags>
  </metadata>
</package>

The values between $ signs will be populated automatically from the projects assembly info (make sure these details are set). The remaining values can be edited or removed.

For a single assembly this is all that is required. However for a Xamarin Forms app you need to add assemblys for the platform specific project. These must be added manually. Add a files section inside the package level:


<files>
    <file src="..\Microlise.XamarinForms.Logging.Droid\Bin\Release\Microlise.XamarinForms.Logging.Droid.dll" target="lib\MonoAndroid" />
    <file src="..\Microlise.XamarinForms.Logging.IOS\Bin\Release\Microlise.XamarinForms.Logging.IOS.dll" target="lib\Xamarin.IOS" />
</files>

We are now ready to create the package…

nuget pack {projectfile}.csproj -Prop Configuration=Release

If this works a .nupkg will be created in the current folder.

Uploading The Package

You can upload your package to your nuget repository of choice. If you are using a network share to as the nuget repository you can add the new package with…

nuget init {folder with .nupkg} \\{nuget share}
Creating Nuget Packages For Xamarin Forms