F# Functional App Development, using Xamarin.Forms

Never write a ViewModel class again! Conquer the world with clean dynamic UIs!

This library allows you to use a variation of elmish, an Elm architecture implemented in F#, to build Xamarin.Forms applications for iOS, Android, Mac and more. The approach to app development is similar to Redux and Flow but targets Xamarin and Xamarin.Forms.

The amount of code I’m not writing is great! @jimbobbennett

Getting started

  1. Install Visual Studio or Visual Studio for Mac and enable both Xamarin and .NET Core support.

  2. Install the template pack:

    dotnet new -i Fabulous.Templates
    
  3. Create a blank F# Functional Xamarin Forms app:

    dotnet new fabulous-app -n SqueakyApp
    
  4. Open, edit, build and deploy in Visual Studio, Visual Studio for Mac and/or “msbuild” command line

    SqueakyApp/SqueakyApp.sln
    

By default iOS and Android projects are created. For WPF apps use --WPF, for example:

Android only:

dotnet new fabulous-app -n SqueakyApp --iOS=false

iOS only:

dotnet new fabulous-app -n SqueakyApp --Android=false

WPF only:

dotnet new fabulous-app -n SqueakyApp --WPF --Android=false --iOS=false
  1. If you are using Visual Studio for Mac and you want to start with File -> New, make sure you target “.NET Standard” to add the references to Fabulous:

    File -> New Solution
    Multiplatform App -> Blank Forms App (F#)
    Shared Code -> Use .NET Standard
    

A Basic Example

Here is a full example of an app:

open Fabulous.Core
open Fabulous.DynamicViews
open Xamarin.Forms

/// The messages dispatched by the view
type Msg =
    | Pressed

/// The model from which the view is generated
type Model =
    { Pressed: bool }

/// Returns the initial state
let init() = { Pressed = false }

/// The function to update the view
let update (msg: Msg) (model: Model) =
    match msg with
    | Pressed -> { model with Pressed = true }

/// The view function giving updated content for the page
let view (model: Model) dispatch =
    if model.Pressed then
        View.Label(text="I was pressed!")
    else
        View.Button(text="Press Me!", command=(fun () -> dispatch Pressed))

type App () as app =
    inherit Application ()

    let runner =
        Program.mkSimple init update view
        |> Program.withConsoleTrace
        |> Program.runWithDynamicView app

The init function returns your initial state, and each model gets an update function for message processing. The view function computes an immutable Xaml-like description. In the above example, the choice between a label and button depends on the model.Pressed value.

Some advantages of using an immutable model are:

Samples

The sample CounterApp contains a slightly larger example of Button/Label/Slider elements.

The sample TicTacToe contains examples of the Grid and Image elements.

The sample AllControls contains examples of instantiating most elements in Xamarin.Forms.Core.

The external sample Calculator is a small calculator app. (Note: because this is an external sample it may not be up-to-date with the latest version of his library.)

The external sample PocketPiggyBank is a small client-server app with login authentication. (Note: because this is an external sample it may not be up-to-date with the latest version of this library.)

The external sample ElmishContacts is a multi-page contacts app featuring maps, group-lists and cross-page messages. (Note: because this is an external sample it may not be up-to-date with the latest version of this library.)

The external sample ElmishPlanets is a multi-page app featuring facts on the planets in the Solar System. It uses Urho3D and Fabulous (Note: because this is an external sample it may not be up-to-date with the latest version of this library.)

See also the curated list Awesome Fabulous.

Further Resources

Presentation: Making Mobile App Development Simple with F#

Presentation: Building mobile apps with F# using Xamarin - Jim Bennett - Xamarin University Guest Lecture

General Docs

Android Setup

iOS Setup

Contributing

Please contribute to this library through issue reports, pull requests, code reviews and discussion.