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<string> GetContactName()
        {
            var intent = new Intent(Forms.Context, typeof(PhonebookActivity));
            Forms.Context.StartActivity(intent);

            var tcs = new TaskCompletionSource<string>();
            EventHandler handler = null;

            handler = (sender, args) =>
            {
                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 && 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

Logging with NLog in Xamarin Forms

This post is a quick demo of how to add logging to a Xamarin Forms application using the NLog library. The complete source code is available here.

NLog is a popular logging library for .net and it’s compatible for Xamarin so it’s a natural choice if you want to add logging to your Xamarin app. It isn’t PCL compatible though, so you do need an implementation for each platform. This isn’t a major problem, and you might want to set the logger up differently for each platform anyway.

Let’s dive into the code…

using System;
namespace LoggingDemo
{
    public interface ILogger
    {
        void Trace(string text, params object[] args);
        void Debug(string text, params object[] args);
        void Info(string text, params object[] args);
        void Warn(string text, params object[] args);
        void Error(string text, params object[] args);
        void Fatal(string text, params object[] args);
    }
}
using System;
using System.Diagnostics.Contracts;
namespace LoggingDemo
{
    public interface ILogManager
    {
        ILogger GetLog([System.Runtime.CompilerServices.CallerFilePath]string callerFilePath = "");
    }
}

In the cross platform project we define a couple of interfaces, ILogManager and ILogger. ILogManager is responsible for creating instances of the ILogger class. ILogger contains the logging message.

In this demo the code for the IOS and Android implementations of the interfaces is pretty much the same. Let’s look at the IOS version…

using NLog;
using NLog.Config;
using NLog.Targets;
using Foundation;
using LoggingDemo.iOS;
using Xamarin.Forms;

[assembly: Dependency(typeof(NLogManager))]
namespace LoggingDemo.iOS
{
    public class NLogManager : ILogManager
    {
        public NLogManager()
        {
            var config = new LoggingConfiguration();

            var consoleTarget = new ConsoleTarget();
            config.AddTarget("console", consoleTarget);

            var consoleRule = new LoggingRule("*", LogLevel.Trace, consoleTarget);
            config.LoggingRules.Add(consoleRule);

            var fileTarget = new FileTarget();
            string folder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            fileTarget.FileName = Path.Combine(folder, "Log.txt");
            config.AddTarget("file", fileTarget);

            var fileRule = new LoggingRule("*", LogLevel.Warn, fileTarget);
            config.LoggingRules.Add(fileRule);

            LogManager.Configuration = config;
        }

        public ILogger GetLog([System.Runtime.CompilerServices.CallerFilePath] string callerFilePath = "")
        {
            string fileName = callerFilePath;

            if (fileName.Contains("/"))
            {
                fileName = fileName.Substring(fileName.LastIndexOf("/", StringComparison.CurrentCultureIgnoreCase) + 1);
            }

            var logger = LogManager.GetLogger(fileName);
            return new NLogLogger(logger);  
        }
    }
}

The NLogManager configures the logging in its constructor. Here we are logging all log entries to the console and logs of warning or above into a file called log.txt. The GetLog function returns an instance of a logger. It uses the CallerFilePath attribute to set the name of the log entries.

using System;
using System.Diagnostics.Contracts;
namespace LoggingDemo
{
    public interface ILogManager
    {
        ILogger GetLog([System.Runtime.CompilerServices.CallerFilePath]string callerFilePath = "");
    }
}

The implementation of ILogger is really simple. It just gives us a bunch of functions to log messages of various levels.

In both of these classes we use the Dependency attribute so that the shared project knows about it.

Now let’s look at using the loggers. The demo app has one screen with buttons which create log entries.

screen-shot-2016-10-16-at-21-40-45

using System;
using System.Collections.Generic;

using Xamarin.Forms;

namespace LoggingDemo
{
    public partial class MainPage : ContentPage
    {
        private static ILogger logger = DependencyService.Get<ILogManager>().GetLog();

        public MainPage()
        {
            InitializeComponent();
        }

        private void Trace_Clicked(Object sender, EventArgs args)
        {
            logger.Trace("Trace Clicked");
        }

        private void Debug_Clicked(Object sender, EventArgs args)
        {
            logger.Trace("Debug Clicked");
        }

        private void Info_Clicked(Object sender, EventArgs args)
        {
            logger.Trace("Info Clicked");
        }

        private void Warn_Clicked(Object sender, EventArgs args)
        {
            logger.Trace("Warn Clicked");
        }

        private void Error_Clicked(Object sender, EventArgs args)
        {
            logger.Trace("Error Clicked");
        }

        private void Fatal_Clicked(Object sender, EventArgs args)
        {
            logger.Trace("Fatal Clicked");
        }
    }
}

We set the logger up as a static variable of the class. Also, the dependency service will create one global static interface of the log manager (this is default behaviour and is easy to forget).

And just to prove it works, here are some log messages appearing in the console…

screen-shot-2016-10-16-at-21-41-15

 

Logging with NLog in Xamarin Forms

A Week In Slovenia

Until five minutes before we landed I want sure I would make it to Ljubljana at all. A massive thundercloud was stubbornly sat over the airfield and the pilots were talking about alternative airports. In the end, after a nervy landing, I made it to Slovenia about three hours later than expected.

I’d wanted to visit Slovenia after reading the book Feral, which featured an amazing chapter about the resurgence of Slovenia’s natural environment, so it was a great place to meet my girlfriend as she travelled round Europe.

IMG_0210

Our first thee nights were in the capital, Ljubljana. After reuniting and leaving my things at the hotel we wandered down to the riverside to visit open kitchen. This is a weekly event on Friday nights throughout summer where local restaurants, food stands, and producers come together at a local market. After checking out the stands and sampling a couple of glasses of wine I picked a salmon burger which was excellent.

The next morning I had planned another food adventure. We met Iva from Ljubljanajam for a food walk around the city. I was really excited about this before I came and it wasn’t a disappointment. We started by exploring the local markets and trying some beautiful fresh produce. As well as showing us food Iva was also telling us more about the city and country. The markets had so much fresh produce from around the country, why can’t we have this at home!?

When I was arranging the food tour I also asked Iva for tips about local restaurants. She recommended Luda so I booked us a table. Hidden away from the main tourist streets this was a real gem, with fresh food creatively cooked. The menu changes weekly to highlight the best produce. I started with courgette with parmesan and walnuts, which, as a courgette fan, was spectacular. My main was prawns with porcini and nectarines, and for dessert I had figs with jasmine ice cream. Both were excellent. Including drinks, the meal was €70 for two, which was an absolute bargain for a real culinary experience.

IMG_0204

After the meal we headed up to the castle via funicular. In summer evenings the castle courtyard turns into a cinema so we finished the day with a film.

For the rest of our time in Ljubljana we saw the sites, stopped at cafes and bars, and had more excellent food. We revisited an excellent gelateria from the food tour, and returned to the castle to take in the views. Ljubljana is small and relaxed for a capital city and it had a great vibe. It’s a perfect weekend destination from the UK.

Our next destination was Kobarid. A small town in the Alps, Kobarid sits in the valley of the Soca River, which is famous for it’s amazing blue colour, excellent water sports, and massive trout.

IMG_0251

On our first evening we went on a quick hike to a viewpoint above the town. On the map this looked easy, but, this is the alps, it was actually pretty tough. It had started to rain, and afternoon rain showers turned out to be a regular feature of our time in the mountains.

Kobarid was the site of intense fighting in the first world war. The Italians fought a futile campaign against the Austro Hungarian Empire in the mountains. We walked the Kobarid Historical Trail which was a great way to spend a day discovering more of this history. The trail visits ancient settlements, the remains of the trench systems, and the Italian Charnel House where many of the bodies were brought after the war. It also visits a spectacular waterfall within a deep canyon. Being the Alps the scenery was typically incredible. It was hard to imagine intense suffering in such a beautiful and peaceful place.

On our last full day in the valley we got to experience the river close up with some whitewater rafting. The blue water looks so inviting but it’s actually freezing cold! I’d never rafted before, although I’ve used to kayak regularly. Once I got used to the lack of control I really enjoyed it. It was exciting without being too scary or physically demanding and a great new perspective on the local scenery.

IMG_0349

On the previous days walk we had watching people jumping from a high rock into the river and I’d casually said ‘I could do that’, so when we stopped at a big rock and were asked if we wanted to jump I had to have a go. It was difficult to climb back down, so we were told if we went up we had to jump. From the water it didn’t look too high but from the top it was a long way down! I’m still not sure if it was the same rock?! After a couple of seconds to think about it I took the plunge!

From Kobarid we headed to Lake Bled via bus then train. This seemed like it was going to be stressful as the times to get from bus to train were very close but in fact it was fine; the train was waiting for the bus to arrive. We’d chosen to get the train journey as it was part of the route from Nova Gorica to Jessnice which was listed as one of the best train journeys you’ve never heard of. It was a nice ride, but I was a little disappointed. It was always pretty but never truly spectacular.

My first impressions of Lake Bled weren’t great. Sure it was scenic but it was also very touristy, with lots of coach tours and massive hotels. It felt like a theme park. The weather had turned and low clouds were blowing in which didn’t help my mood. We visited the castle, which I found underwhelming, and spent the rest of the day hiding from the rain with a few glasses of wine.

IMG_0421

The next day the weather had improved and so had my mood. We took the day to walk around the lake – only 6km but with lots of places to stop. Away from the tourist end of the lake it was much nicer. As we made our way around we stopped to swim, then headed up to viewpoint which had been recommended to us.

As in Kobarid, this was’t just a gentle stroll, it was steep and exposed in places, and muddy from the recent rain. In the heavy woods I wondered if we would even be able to see anything when we reached the top.

There was nothing to worry about! A short scramble from the summit we found a truly spectacular view. This was the postcard image of Lake Bled, the church on it’s island, the castle on it’s hill, with the alps rising majestically behind. For me this was a highlight of Bled. There are actually 3 viewpoints, but the one at the very top was the best by far. This was the summit of Velika Osojnica, and can be found from paths at the west end of the lake.

IMG_0438

After returning to the shores of the lake and a well deserved beer we got out on the water with stand up paddle boards. This was another first for me and it was surprisingly easy. We had the run of the lake so we paddled around the island along with the local plenta boats.

From Bled I had to return to the airport. Slovenia was everything I expected. Ljubljana is a great little city with excellent food and drink, perfect for a quick break. The alps are the alps, and it was good to see them in a less developed environment than in France. The week was a great mix between the city and the outdoors. This was my first time in Slovenia but it won’t be my last.

A Week In Slovenia

Xamarin Forms Custom Renderers

In Android Lollipop button text defaults to upper case. The default Button in Xamarin Forms will also appear in all caps. In this post I show how to use a custom renderer to make the text preserve its casing.

The code for this sample is available here. Here’s what it looks like running on Android and IOS.

Screen Shot 2016-05-09 at 21.54.08
Android
Screen Shot 2016-05-09 at 21.50.34
IOS

The Custom Renderer lets us access the properties of the platform specific button – in this case the Android Button. To achieve this we need to subclass the button in the cross platform project. This doesn’t need to do anything, it just provides a class to use in the XAML which can be targeted by the platform specific renderer…

using System;
using Xamarin.Forms;

namespace ButtonCustomRenderer
{
	public class CustomButton : Button
	{
	}
}

… and the make the custom button available in the XAML by adding it’s namespace at the top…

<?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="ButtonCustomRenderer.DemoPage"
				xmlns:local="clr-namespace:ButtonCustomRenderer;assembly=ButtonCustomRenderer">
	<ContentPage.Content>
		<StackLayout Padding="10, 20, 10, 10">
			<Button Text="This is a standard button" />
			<local:CustomButton Text="This is a custom button" />
		</StackLayout>
	</ContentPage.Content>
</ContentPage>

Then we add create the renderer in the platform specific project…

using System;
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms;
using ButtonCustomRenderer;
using ButtonCustomRenderer.Droid;

[assembly: ExportRendererAttribute (typeof(CustomButton), typeof(CustomButtonRenderer))]
namespace ButtonCustomRenderer.Droid
{
	public class CustomButtonRenderer : ButtonRenderer
	{
		protected override void OnElementChanged(ElementChangedEventArgs&lt;Xamarin.Forms.Button&gt; e)
		{
			base.OnElementChanged(e);

			if (Control != null)
			{
				Control.SetAllCaps(false);
			}
		}
	}
}

The custom renderer subclasses ButtonRenderer, not CustomButton. All it has to do is override OnElementChanged and make the necessary changes to the Android Button object it provides. I just set all caps to false.

The ExportRendererAttribute is used to tie the renderer to the custom button in the cross platform project.

In this example the IOS button doesn’t need any changes. This means we don’t need a custom render in the IOS project – the app doesn’t need one to work either.

Xamarin Forms Custom Renderers

Using The Xamarin Forms AbsoluteLayout

I was struggling to get to grips with the Xamarin Forms AbsoluteLayout. To understand I made a demo app. This post is what I found. The sample code is available here. Here’s the app:

Screen Shot 2016-05-02 at 11.58.31
Default settings

At the top of the screen there is a dark blue BoxView within an AbsoluteLayout. The first table controls the position and bounds of the box The second table controls the AbsoluteLayoutFlags that are used.

By default the AbsoluteLayoutFlags.All is on which means that all coordinates are proportional. The box is half the size of its parent because it’s width and height are set to 0.5. The X and Y values are 0.5 as well which centres the box. X and Y values position the centre of the box, not the top left corner.

With proportional coords turned on X or Y values of 0 or 1 will put the child at the edge of it’s parent; you don’t need to do any calculations to work it out. For example 0 and 0 for the top left corner.

Screen Shot 2016-05-02 at 12.16.19
0,0 for top left

Values below 0 or above 1 will position the box outside of its parent. Similarly setting the width or height above 1 will cause it to overflow.

Screen Shot 2016-05-02 at 12.17.23
X = -0.5
Screen Shot 2016-05-02 at 12.18.06
Width -= 1.5

Using the flags you can set some or all of the coordinates to be proportional. With proportional coords turned off the position and size are specified in device units.

Screen Shot 2016-05-02 at 12.39.26
Device coords

Obviously you need to be careful with this as the positioning won’t be the same on different displays and screen sizes.

I’ve used a XAML view for the app, here’s the AbsoluteLayout.

<AbsoluteLayout HorizontalOptions="Fill"
                 VerticalOptions="FillAndExpand"
                 BackgroundColor="#4C688B">
     <BoxView Color="#051B38" AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0.5, 0.5, 0.5, 0.5" x:Name="BoundsBox"/>
</AbsoluteLayout>

Setting up app to update the bounds when the sliders changed was a little tricky. The flags and bounds properties of the box are readonly and can only be set via SetLayoutBounds – This needs to be called each time a value changes.

private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    var viewModel = (DemoPageViewModel)sender;
    AbsoluteLayout.SetLayoutBounds(this.BoundsBox, new Rectangle(viewModel.X, viewModel.Y, viewModel.Width, viewModel.Height));
}
Using The Xamarin Forms AbsoluteLayout