Thursday, August 17, 2017

Popped Pages in Xamarin Forms

This post is long overdue. About a year ago (July 2016) I managed to get some code into Xamarin Forms Core. This code change was necessary in order to make TinyPubSub work correctly.

TLDR;


If you call Navigation.PopToRoot() in Xamarin Forms and want to know all the pages being popped you need to cast the NavigationEventArgs to a PoppedToRootEventArgs.

    var page = new NavigationPage();
     page.PoppedToRoot += (object sender, NavigationEventArgs e) => 
     {
         // Typecast the args
         var args = e as PoppedToRootEventArgs;

         // Get the pages
         var poppedPages = args.PoppedPages;
     };

Long story


There was quite a long discussion before I got this change approved by Jason Smith and the Forms team. The most pressing issue was that we could not break the signature of the PoppedToRoot event so we ended up creating a new event args class (called PoppedToRootEventArgs) and simply passed that one in. 

This of course hides the PoppedToRootEventArgs from plain sight so you need to know what you are looking for.

The internal workings of PopToRoot (the important parts) looks like this:

    var args = new NavigationRequestedEventArgs(RootPage, animated);

     EventHandler<NavigationRequestedEventArgs> requestPopToRoot = PopToRootRequested;
     if (requestPopToRoot != null)
     {
         requestPopToRoot(this, args);

         if (args.Task != null)
             await args.Task;
     }

    PoppedToRoot?.Invoke(thisnew PoppedToRootEventArgs(RootPage, childrenToRemove.OfType<Page>().ToList()));
        

The last line is the event (PoppedToRoot) and as you see we pass in PoppedToRootEventArgs as the args.

The PoppedToRootEventArgs is simply a class inheriting from NavigationEventArgs that adds PoppedPages as a IEnumerable to the class.

    public class PoppedToRootEventArgs : NavigationEventArgs
    {
        public PoppedToRootEventArgs(Page page, IEnumerable<Page> poppedPages) : base(page)
        {
            if (poppedPages == null)
                throw new ArgumentNullException(nameof(poppedPages));

            PoppedPages = poppedPages;
        }

        public IEnumerable<Page> PoppedPages { getprivate set; }
    } 

Thursday, July 20, 2017

TinyPubSub makeover - arguments and new super hero publish features

I finally got around to give TinyPubSub a well deserved make over by adding some features that have been requested for a while. The toughest part is to keep it Tiny and not add to much bells and whistles to it.

I also got some great help from my friend Daniel Hindrikes to set up a devops flow that will help me manage pull requests and nuget-package publishing.

The features added to this version are;

  • Publish with arguments
  • Publish using fire-and-forget (with or without argument)
  • Publish async (with or without argument)

Publish with argument


You can now subscribe and pass an argument of the type Action<string>:

  TinyPubSub.Subscribe("test", (x) => Log.WriteString(x));

And publish it by simply adding another argument:

  TinyPubSub.Publish("test""duck");

In order to keep it tiny we only allow for a single string argument at the moment. We did explore a whole bunch of alternatives, including generics and dynamic objects and stuff but we settled for this at the moment.

Publish using fire and forget (PublishAsTask)


Using a simple Publish in TinyPubSub is synchronous and will stop the execution flow until all the subscribers have executed their code. We've now added a way to publish events fire-and-forget style.

  TinyPubSub.PublishAsTask("test""duck");

Publish async


And the last way is to simply publish async. Works as expected.

  await TinyPubSub.PublishAsync("test""duck");

Resources

Sunday, March 12, 2017

Xamarin for the non-xamarinist

 A Xamarin introduction

This is a post about some facts you need to know to get started with Xamarin development. It's not code centric so the target audience would be someone who's interested in the basic Xamarin facts.

We assume that the target platforms are iOS and Android. It’s worth pointing out that Xamarin (and especially Xamarin Forms) can target Windows Phone, Windows Desktop Apps and Mac OS X apps as well.

Specific requirements for iOS

Apple requires that all iOS apps are built on OS X which in turn only can run on Apples hardware. This means that you must have a Mac to build iOS apps. Xamarin also uses the XCode toolchain for compiling the app,
There are some approaches to this:
  • The first hand recommendation is to use a MacBook (Air/Pro) with Parallels Desktop (virtualization software) to run Windows on the same machine. This allows for a seamless transition between OS X and Windows, enabling the developer to use Visual Studio to develop iOS apps.
  • The second hand recommendation (perhaps in combination with the first recommendation) is to acquire a Mac Mini as a local build server. A windows client can connect to this build server and send all iOS builds to it. There is also the possibility to remote access the simulator directly from within Visual Studio. If you have a Windows computer (like a SurfaceBook) you also get multipoint touch in the simulator.
  • Another option for build is to use Visual Studio Mobile Center (currently in preview) to take care of the builds for you. It’s a wrapper on top of multiple Azure services.

 Xamarin Forms or Traditional Xamarin development

One thing you have to do early in the project is to get a good grip of the difference between Xamarin Forms and Traditional Xamarin development.

Xamarin Forms is a GUI abstraction that renders fully native user interfaces. It allows for a shared GUI codebase with the drawback of pixel perfect designs.

Traditional Xamarin Development is best if you have a lot of differences between the platform user interfaces or simply like storyboarding and axml.

Regardless of which approach you take you should strive for moving as much of the logic away from the GUI and into shared code base as possible.

Xamarin Forms

Xamarin Forms is a platform on top of Xamarin that abstracts the GUI-code (Xaml or C#) but still renders 100% native user interfaces.

It is very possible to make beautiful apps in Xamarin Forms but it still requires that you have knowledge about the underlying platform. You also have to ability to drop down into platform specific code at any moment. Especially through the user of Dependency Injection which plays a vital role in a cross platform mobile architecture . You also have the ability to create separate views for each platform even if you declare them in the shared library.

The most common architecture to use when writing a Xamarin Forms application is MVVM. There are a lot of tooling and resources available.

The basic idea in forms is that you declaratively define you UI using XAML or C#. Most common is to use XAML. For example, a button in XAML could look like this: <Button Text=”My Button” />. When this renders (or compiles if you use Compiled Xaml) this is turned into a UIButton on iOS and a Button on Android. The conversion between abstract and concrete classes is done by the concept of Renderers. Every renderer can be extended or replaced. You can also write your own renderer. There is no hidden magic.

And it’s all open source.

Traditional Xamarin Development

In traditional development you define the GUI in the same way that you do it when developing apps using the vendor specific tooling. (Java in Android Studio or Swift/Objective-C in Xcode). On iOS that usually means Storyboarding and on Android you are most likely defining the GUI in axml-files. You could also write it using C#, but it tends to be a lot of code to write.

You can still (and should) choose to use an MVVM-framework to move all the common code out of the views.

UI Testing

When it comes to Android specifically, UI Testing is a must and it’s highly recommended that you find some tooling that helps you with this.
Xamarin Testcloud is one of those tools/services that allows you to run your app on thousands of hardware devices with the weirdest combination of OS versions installed. You simply cannot do this in an affordable way yourself.

You author your tests locally first, in code or with a test recorder. Then you submit the tests and a build to TestCloud and select what devices you want to run it on. You pay by the device minute used.

It also works perfectly for iOS and even for apps that aren’t written in Xamarin at all.

The other great benefit of Testcloud (or services like Testcloud) is that you can recreate bugs on the actual device/OS combo that the bug was spotten on without having to buy that specific device.

Architectures and plugins

This is the current list of components/nuget-packages/services that I currently recommend using in a Xamarin App.
·       Autofac – Dependency injection.
·       MVVM – I often use Vanilla MVVM with a simple base class for the most common stuff..
·       PropertyChanged.Fody – IL injection (weaving) of INotifyPropertyChanged. ViewModels get’s a lot smaller and code readability increases.
·       Acr.Dialogs – An abstract way to use common system dialogs (think UIAlert etc.)
·       Akavache – Cache amd SQLite databas packaged for Xamarin. Also supports secure and encrypted app based storage.
·       HockeyApp – Error tracking and usage tracking.
·       Newtonsoft – Json serializer
·       TinyPubSub – Very simple PubSub handler for internal communication.
·       Xam.Plugin.Connectivity – Plugin for handling network changes
·       Xam.Plugin.Geolocator – Plugin for handling GPS
·       Xam.Plugin.Media – Plugin for handling camera and media
·       Xam.Plugin.Settings – Cross platforms settings
·       Xam.Plugin.Vibrate – Plugin for handling vibration
·       ZXing.Net.Mobile – Bar code scanner if one should be needed.



Wednesday, November 9, 2016

TinyPubSub 1.1 released

I just released TinyPubSub.Forms 1.1 that takes advantage of the change I got into Xamarin.Forms Core Navigation.

Nuget package for Forms can be found at https://www.nuget.org/packages/tinypubsub.forms/.

The change is that we now can get info from the NavigationPage what pages that are popped when we call PopToRoot. We needed this information to deregister pages in TinyPubSub.

Tuesday, October 11, 2016

PropertyChanged.Fody

Short story
When using MVVM as the pattern of choice for your app, make sure to use PropertyChanged.Fody to make your life a little easier. 
  1. Install the nuget-package PropertyChanged.Fody
  2. If using Xamarin studio, edit the Weavers.xml file in the root and add <PropertyChanged>. This is done automatically in Visual Studio.
  3. Create a base class for ViewModels and decorate it with the [ImplementPropertyChanged]attribute
  4. All your properties will be raising the PropertyChanged event on INotifyPropertyChanged.
Long story
MVVM heavily relies on ViewModels that implement INotifyPropertyChanged. This is the way that the View will be aware of changes in the ViewModel and what triggers UI-updates when you change a ViewModel property.

Before PropertyChanged.Fody

The usual way to tackle this is to implement the INotifyPropertyChanged your self. INotifyPropertyChanged only defines one event called PropertyChanged. This event is what the view hooks up to in order to listen to the ViewModel. No magic at all going on here.
So what we do is that we implement that interface and add a method to raise it in a simple way.
using System.ComponentModel; // The definition lives here

public class MyViewModel : INotifyPropertyChanged
{
    // The only thing INotifyPropertyChanged defines
    public event PropertyChangedEventHandler PropertyChanged;
   
    // Helper method to raise the event
    protected void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    
    // And a property with a backing field
    private string _name;
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
            RaisePropertyChanged("Name");
        }
    }
} 
That is alot of code for a single property. What if we could get rid of most of that? 

After PropertyChanged.Fody

Enter PropertyChanged.Fody!
To install, do this:
  1. Install the nuget-package PropertyChanged.Fody
  2. If using Xamarin studio, edit the Weavers.xml file in the root and add <PropertyChanged>. This is done automatically in Visual Studio.
After installing the nuget package, rewrite the code above to look like this.
[ImplementPropertyChanged]
public class MyViewModel 
{
    public string Name {get; set; }
} 

Can we make it better

Yes, create a base class for your ViewModels and decorate that one with the ImplementPropertyChanged attribute. Then you can forget about it.

How does it work

Fody is an IL-weaver. It modifies the IL code generated by the compiler and implements the interface for you.

Resources

Make sure to check out the official documentation at https://github.com/Fody/PropertyChanged

Tuesday, July 26, 2016

Thoughts on making TinyPubSub a little less tiny

Thoughts on making TinyPubSub a little less tiny

TinyPubSub is a very simple Publish/Subscribe library created mainly for passing events between views in an Xamarin Forms application that uses MVVM. You can read about it at https://github.com/johankson/tinypubsub.
What I'm thinking about doing is extending it with two features
  • Passing of data
  • A stack based recipient model

Passing of data

TinyPubSub only allows for publishing events from one source to many recipients. It was originally create for notifying other views to reload or refresh their data. At first this was pretty much all it was intended to do. But now I can't help myself and I would really like to publish data as well.
This is the original way to subscribe and publish an event.
In the first view model
TinyPubSub.Subscribe("ducks-loaded", 
   () => { RebindGui(); });
In another view model
TinyPubSub.Publish("ducks-loaded");
Let's say I want to pass data, it could look like this
TinyPubSub.Subscribe("duck-color-updated", 
   (c) => { RecolorDuck( c ) } );
And in the publish part
TinyPubSub.Publish("duck-color-updated", c);

An example

Let's say you're buildning an app for configuring a car. The first page is to choose the model. On this page there is a button to choose your color. The original page simply registers for the color-chosen event and waits happily for that to happen. We then create a generic choose color page that knows nothing about what page that really needs that color. When the color finally is choosen the page fires a color-chosen event and the first page will receive it.
All is fine until you get another subpage that also wants a color choosen. You can solve that in a number of ways. The first being to register different events for different colors choosers and pass an argument to when we create the color picker page. This is messy and could easily get out of hand.
My proposed solution is to create a function where you can state that only the latest registered listener will handle the event.

A stack based recipient model

Enter the stack based recipient model.
The mechanism behind this is simple. The latest registered recipients of a specific event is the only one that will receive an event.
Since all events for a page is deregistered automatically in TinyPubSub it will be simple to reuse the color-picker page multiple times.
To revisit the car example, just before clicking the button for coloring your car door you register to the color-chosen event with the `SubscribeExclusive(...) method.
TinyPubSub.SubscribeExclusive("color-chosen", 
   (c) => { RecolorCarDoor( c ) } );
await Navigation.PushAsync(Resolver.Resolve());
Then it doesn't matter if you have another page listening for the color-chosen event. Only the page before will get the event. And when the page goes out of scope, the subscription for the event will be removed and the page before will get the event instead.
This also means that the ColorPickerPage could check at runtime to see if there are any recipients at all and throw an Exception if there is none.

Summary

This is still not implemented. I thought I just write it down first and get some comments on it.