DEV Community

Cover image for Getting Elmish in .NET with Elmish.WPF
Matt Eland
Matt Eland

Posted on • Originally published at killalldefects.com on

Getting Elmish in .NET with Elmish.WPF

Let’s talk about Elmish.WPF and how it brings Model View Update (MVU) architecture and Functional Programming to desktop .NET development.

In this article I’ll share the results of my early journey in learning Elmish.WPF and walk you through setting up a new project. Don’t know what Elmish.WPF is? That’s fine – I barely knew myself. I’ll teach you everything you need to know.

My main goal for you in reading this is that you:

  • Learn what Elmish.WPF is
  • Understand how to get started with Elmish.WPF
  • Think about the advantages F# and Model View Update (MVU) application architectures bring to the table

Along the way, we’ll cover:

  • What is Elm anyway?
  • What Elmish.WPF is and how it helps with XAML applications
  • The differences between MVVM and MVU application architectures
  • Installing and referencing Elmish.WPF
  • Hosting WPF content from an F# library
  • Creating a XAML control library to represent static views

If you’re a .NET developer I encourage you to give this a read, even if you aren’t extremely interested in desktop or mobile development. Elmish style architectures are spreading and understanding Model View Update at a high level will help you down the road.

If you haven’t worked with F# or WPF, you should be fine to read the article, but if you’ve never worked with Visual Studio or .NET technologies before, this is likely not the article to start with.

Elmish? What is this? Middle Earth?

Recently I’ve been seeing the term “Elmish” floating around a lot more. Part of this is my interest in F# and other functional programming languages, but I also see the term come up more often in my existing circles.

This is supported by the following Google trend results over the past 5 years:

While it’s not a huge spike, there’s clearly an increased frequency in interest in the topic over the last few years – primarily when paired with searches on F#, React, or Fable.

So what is Elmish?

Essentially, Elmish refers to languages espousing Elm-like patterns. Elm is a functional programming language used to generate JavaScript – including code to manage the rendered DOM.

Elmish languages are functional programming languages that also follow the Model View Update (MVU) pattern which has the following basic components:

  • Relies on an immutable model
  • Populates a view based on the current model
  • Sends messages on events in the user interface
  • Updates the effective model by feeding the old model and the messages into a Reducer

Why is this attractive?

Well, for one, the use of immutable state and reducers prevents a number of quality issues.

For another, functional programming is a fantastic way of improving software quality. See my prior article on why .NET managers should strongly consider F# for more information on my views on functional programming.

Essentially, following a MVU architecture is going to be weird and different and may slow some development efforts up front, but will simplify and improve your maintenance work in the long term. This happens via functional programming’s tendency to eliminate entire classes of defects and reducer-based architectures making bugs easy to isolate and resolve.

An Introduction to Elmish.WPF

Now that we talked a bit more about Elmish languages and the idea of MVU, let’s introduce Elmish.WPF.

Elmish.WPF is a library that allows you to build Windows Presentation Foundation (WPF) desktop applications using Elmish principles.

Typically in WPF, we follow Model View ViewModel (MVVM) architecture as pictured below:

Elmish.WPF lets us work with immutable models that are swapped out based on user actions.

Because we’re working with immutable state, the need for property changed notifications via the ViewModel is reduced or eliminated and so MVVM makes less sense than a MVU-based architecture like Elmish.WPF’s.

Elmish lets you run a core MVU logic that eliminates the need to create ViewModel classes while still allowing you to build powerful user interfaces with XAML like you’re used to.

Let’s take a look at how this works and how to get started with Elmish.WPF.

Getting Started with Elmish.WPF

Creating the Projects

First, you’ll need to create an F# .NET Core Console Application (Elmish.WPF also works for .NET Framework, but I’ll only be covering .NET Core in this article).

We’ll do this in Visual Studio 2019 Community Edition for the purposes of this article.

Don’t worry about the use of the console application in the project type. We’ll be modifying the properties of this project to customize it. This project will be the main entry point of our application and hold the main Elmish processing loop.

Next, we’ll add a C# WPF Custom Control Library (.NET Core) project to the solution:

This C# project is going to hold our XAML views. We need to use C# for this because F# does not support definitions of XAML files yet – at least in Visual Studio.

Next, add a reference from your F# project to your C# library so that we can reference the main application views.

Before we can add Elmish.WPF to the mix, we should define our model and view.

Let’s do that next.

Creating the View

In the WPF Control Library project, add a new Window called MainView.xaml:

We’re just going to be doing some very simple things in this example. Specifically, we want to have a button for the user to click and display the number of times the button has been clicked.

Not the most Earth-shattering code, but enough for a simple demo application.

The XAML for this is pretty simple.

Inside the generated XAML file, replace the <grid></grid> code with the following markup:

Note that I’m not including the full XAML file as your namespace is going to be different than mine and we don’t actually need to import any new namespaces for the above code to work.

Creating the Data Model

Next let’s write some code to handle storing the application state.

In our F# project, add the following definition to the top of the program.fs file:

This is an incredibly simple model, but we really don’t need a lot for our example.

Note that the names in the Model type do not need to be the same things you’re binding to in the view. The Model type isn’t what the view uses as its DataContext and, because of that, we can name our properties whatever we want.

Now that we have our model and view in place, let’s add Elmish.WPF to the scene to tie everything together.

Referencing Elmish.WPF

Manage NuGet Dependencies for your F# project and add a reference to Elmish.WPF as pictured below:

Now, we can start modifying our project to work with Elmish.WPF.

Adding WPF Support to the F# Project

This is the least fun aspect of this, but I’m sorry – we’re going to have to edit a project file.

We’ll need to edit our F# project’s .fsproj file and add the UseWPF node to its PropertyGroup element as shown below:

Note that I’ve included my full .fsproj file contents for reference, but you’ll only need to add that one UseWPF node pictured above.

Save that and close the file.


Next, we’ll need to tweak some settings in Visual Studio to tell Visual Studio to launch our application as a Windows Application, not a console application.

Go into project settings for your F# application and change the startup mode to Windows Application as pictured below:

This step is technically optional, but if you don’t do this you’ll later see both your application window and a console window open up, which is not what you want to see.

Building the Elmish.WPF Processing Loop

Phew. All that work to set up our projects was unfortunate, but thankfully that’s one-time work and most of the hoops we jumped through were because F# does not yet support XAML content.

Now we can actually focus on what we came here for – learning Elmish.WPF!

We’ll be working entirely in Program.fs for this section.

First, add an open Elmish.WPF statement to the top of the file so that we can work with the main Elmish.WPF framework.

While you’re at it, you’ll need to add an open statement for the same namespace that your MainWindow was defined in. Check the MainWindow.xaml.cs file for that namespace as it will be different based on what you named your project.


Remove the existing default program code at the bottom of your program.fs file. You’re not running a console application and so you won’t need it. Instead, add the following:

So, this won’t compile at the moment, and there’s a lot going on here and we should talk about that.

First, on line 2, we define attributes telling F# that this is the application entry point and it should run in an appropriate threading model.

Next, we invoke the Elmish.WPF extension method of mkSimpleWpf to create a standard Elmish.WPF application.

This function needs three arguments:

  1. An init function to generate the application’s starting state
  2. An update function to act as a reducer to generate a new state based on a message
  3. A bindings function to provide information to the auto-generated DataContext the View will be bound to.

We’ll go over each one of these functions in the next section.

Finally, we execute runWindow and specify a new Window instance for the application to display. This instance we provide is the MainWindow we defined in our WPF Control Library project earlier.

Implementing the Core Functions

Let’s look at how to implement the init, update, and bindings functions.

init (Starting State)

The easiest of the three, the init function just returns an instance of Model in its starting state.

Ours looks like this:

Note that I’ve included the Model we defined earlier in the above snippet for reference.

update (The Reducer)

Update gets a bit trickier.

Since update relies on a message, we’re going to have to create a Discriminated Union of the types of messages we expect. I’ll call this type MessageType and give it the options of a button click event or a reset event, even though our view doesn’t actually have a button for the latter.

It looks like this:

Note that MessageType is almost an enum here (it would be if we explicitly assigned values to things), but we’re keeping it as a discriminated union as future message types may have state associated with them (this will be covered in a future article).


Now that we have our MessageType defined, we can implement the update function.

The update function takes in a MessageType and the old Model and outputs a new Model. How you do that is up to you, but I strongly recommend using F#’s match syntax as shown here:

Here we match over the various supported message types and return a new state based on the operation. In the case of Reset, we just call init again giving us our starting state.

In the case of ButtonClicked, we use F#’s with syntax to create a clone of model with only a minor difference: the ClickCount property should have a value 1 higher than the prior model did.

That’s it. Just a simple reducer that performs simple operations.

If your operations get complex, I strongly recommend you pull them into their own functions and simple invoke those functions from the update method. This is exactly what we’re doing with the call to init() on line 5.

bindings (DataContext Generation)

Finally, we get to the binding function which configures an auto-generated data context object.

The syntax of this is a little odd, but we’re effectively just building a list of properties on an object and configuring how they behave.

Let’s jump into the code:

The one-way bindings on lines 4 and 5 are fairly simple. We use Binding.oneWay to specify a function that returns a value from our model and exposing it as a property named the string at the beginning of the line.

For example, line 5 declares a new property named “Message” and grabs the value for it from the Model‘s Message property.

The commands generate an ICommand instance that WPF can bind many controls to. In our case, the button is will be bound to the ClickCommand property and will invoke this command when executed.

The Binding.cmd ButtonClicked syntax tells Elmish.WPF to:

  • Create an ICommand binding
  • Send a message to update with the ButtonClicked MessageType specified as well as the current model.
  • Re-evaluate bindings to update the view with the new model.

Tying it all together

And that’s all there is to it.

Now when we run we’ll get a fantastic button that we can click to our heart’s content and watch the counter update itself in real time.

For reference, my complete Program.fs is included below:

Next Steps & Closing Thoughts

Hopefully this adequately explains Elmish / MVU architectures and how to get started with Elmish.WPF as well as why you might want to.

I’m still early on in my evaluation of the technology and will be looking to follow up this article with larger-scale examples and practices on something other than a trivial starter application.

Because of this, I’m reserving judgement on recommending Elmish.WPF, but I wanted to share this first leg of the journey with others so that they could understand Elmish.WPF better and learn more about how it works and how they could get started with it.

For next steps, I strongly recommend reading the Elmish.WPF Tutorial online as it gets into much more complex binding scenarios and capabilities.

The post Getting Elmish in .NET with Elmish.WPF appeared first on Kill All Defects.

Latest comments (2)

Collapse
 
shimmer profile image
Brian Berns • Edited

I've implemented a number of WPF MVVM apps in F# with immutable models using Reed Copsey's ViewModule and FsXaml libraries. Do you have any experience with that approach? If so, how would you compare it to Elmish? If not, maybe I'll take a shot at comparing the two.

Collapse
 
integerman profile image
Matt Eland

I have mild familiarity with the two but have never used them myself. I'd love to hear your thoughts.