# Elmish.WPF **Repository Path**: hopefsharp/Elmish.WPF ## Basic Information - **Project Name**: Elmish.WPF - **Description**: No description available - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-09-16 - **Last Updated**: 2025-04-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README WPF done the Elmish Way ======================= [![NuGet version](https://img.shields.io/nuget/v/Elmish.WPF.svg)](https://www.nuget.org/packages/Elmish.WPF) [![NuGet downloads](https://img.shields.io/nuget/dt/Elmish.WPF.svg)](https://www.nuget.org/packages/Elmish.WPF) [![Build status](https://github.com/elmish/Elmish.WPF/actions/workflows/continuous_integration.yml/badge.svg)](https://github.com/elmish/Elmish.WPF/actions/workflows/continuous_integration.yml) **The good parts of MVVM (the data bindings) with the simplicity and robustness of an MVU architecture for the rest of your app. Never write an overly-complex ViewModel class again!** ### Elevator pitch Elmish.WPF is a **production-ready** library that allows you to write WPF apps with the robust, simple, well-known, and battle-tested MVU architecture, while still allowing you to use all your XAML knowledge and tooling to create UIs. Some benefits of MVU you’ll get with Elmish.WPF include: * Simple-to-understand, unidirectional data flow * Single source of truth for all the state in your app * Simple async/IO * Immutable data * Pure functions * Great testability * Simple optimization * 78% more rockets 🚀 Even with static views, your central model/update code can follow an idiomatic Elmish/MVU architecture. You could, if you wanted, use the same model/update code to implement an app using a dynamic UI library such as [Fabulous](https://github.com/fsprojects/Fabulous) or [Fable.React](https://github.com/fable-compiler/fable-react), by just rewriting the “U” part of MVU. **Static XAML views is a feature, not a limitation. See the FAQ for several unique benefits to this approach!** Elmish.WPF uses [Elmish](https://github.com/elmish/elmish), an F# implementation of the MVU message loop. Big thanks to [@MrMattSim](https://github.com/MrMattSim) for the wonderful logo! ### Sponsor [![JetBrains logo](jetbrains.svg)](https://www.jetbrains.com/?from=Elmish.WPF) Thanks to JetBrains for sponsoring Elmish.WPF with [OSS licenses](https://www.jetbrains.com/community/opensource/#support)! Recommended resources --------------------- * The [Elmish.WPF tutorial](https://github.com/elmish/Elmish.WPF/blob/master/TUTORIAL.md) explains how to use Elmish.WPF, starting with general Elmish/MVU concepts and ending with complex optimizations. * The [Elmish.WPF binding reference](https://github.com/elmish/Elmish.WPF/blob/master/REFERENCE.md) explains Elmish.WPF's bindings and library functions for modifying bindings. * The [Elmish docs site](https://elmish.github.io/elmish) also explains the general MVU architecture and principles. * The [Elmish.WPF samples](https://github.com/elmish/Elmish.WPF/tree/master/src/Samples) provide many concrete usage examples. * Blog posts: * [Getting Elmish in .NET with Elmish.WPF](https://medium.com/swlh/getting-elmish-in-net-with-elmish-wpf-cd44e3eddc27) ("getting started" guide by Matt Eland) * Elm resources may also provide some guidance, but note that not everything is relevant. A significant difference between “normal” Elm architecture and Elmish.WPF is that in Elmish.WPF, the views are statically defined using XAML, and the “view” function does not render views, but set up bindings. See the [tutorial](https://github.com/elmish/Elmish.WPF/blob/master/TUTORIAL.md) for details. * [Official Elm guide](https://guide.elm-lang.org) * Two talks: [Summarising Elm scaling strategy](https://dev.to/elmupdate/summarising-elm-scaling-strategy-1bjn) * Reddit: [Resources regarding scaling Elm apps](https://www.reddit.com/r/elm/comments/65s0g4/resources_regarding_scaling_elm_apps/) * Reddit: [How to structure Elm with multiple models](https://www.reddit.com/r/elm/comments/5jd2xn/how_to_structure_elm_with_multiple_models/dbuu0m4/) * Reddit: [Elm Architecture with a Redux-like store pattern](https://www.reddit.com/r/elm/comments/5xdl9z/elm_architecture_with_a_reduxlike_store_pattern/) Getting started with Elmish.WPF ------------------------------- See the [SingleCounter](https://github.com/elmish/Elmish.WPF/tree/master/src/Samples) sample for a very simple app. The central points are (assuming up-to-date VS2019): 1. Create an F# Class Library. If targeting .NET 5 or .NET Core, the project file should look like this: ```fsproj net5.0-windows true ``` If targeting .NET Framework (4.6.1 or later), replace the first line with ```fsproj ``` 2. Add NuGet reference to package `Elmish.WPF`. 3. Define the model that describes your app’s state and a function that initializes it: ```F# type Model = { Count: int StepSize: int } let init () = { Count = 0 StepSize = 1 } ``` 4. Define the various messages that can change your model: ```F# type Msg = | Increment | Decrement | SetStepSize of int ``` 5. Define an `update` function that takes a message and a model and returns an updated model: ```F# let update msg m = match msg with | Increment -> { m with Count = m.Count + m.StepSize } | Decrement -> { m with Count = m.Count - m.StepSize } | SetStepSize x -> { m with StepSize = x } ``` 6. Define the “view” function using the `Bindings` module. This is the central public API of Elmish.WPF. Normally in Elm/Elmish this function is called `view` and would take a model and a dispatch function (to dispatch new messages to the update loop) and return the UI (e.g. a HTML DOM to be rendered), but in Elmish.WPF this function is in general only run once and simply sets up bindings that XAML-defined views can use. Therefore, let’s call it `bindings` instead of `view`. ```F# open Elmish.WPF let bindings () = [ "CounterValue" |> Binding.oneWay (fun m -> m.Count) "Increment" |> Binding.cmd (fun m -> Increment) "Decrement" |> Binding.cmd (fun m -> Decrement) "StepSize" |> Binding.twoWay( (fun m -> float m.StepSize), (fun newVal m -> int newVal |> SetStepSize)) ] ``` The strings identify the binding names to be used in the XAML views. The Binding module has many functions to create various types of bindings. Alternatively, use statically-typed view models in order to get better IDE support in the XAML. ```f# open Elmish.WPF type CounterViewModel(args) = inherit ViewModelBase(args) member _.CounterValue = base.Get() (Binding.OneWayT.id >> Binding.mapModel (fun m -> m.Count)) member _.Increment = base.Get() (Binding.CmdT.setAlways Counter.Increment) member _.Decrement = base.Get() (Binding.CmdT.setAlways Counter.Decrement) member _.StepSize with get() = base.Get() (Binding.OneWayT.id >> Binding.mapModel (fun m -> m.StepSize)) and set(v) = base.Set(v) (Binding.OneWayToSourceT.id >> Binding.mapMsg Counter.Msg.SetStepSize) ``` 7. Create a function that accepts the app’s main window (to be created) and configures and starts the Elmish loop for the window with your `init`, `update` and `bindings`: ```F# open Elmish.WPF let main window = Program.mkSimple init update bindings |> Program.runElmishLoop window ``` Alternatively, use a statically-typed view model at the top level. ```F# open Elmish.WPF let main window = Program.mkSimpleT init update CounterViewModel |> Program.runElmishLoop window ``` In the code above, `Program.runElmishLoop` will set the window’s `DataContext` to the specified bindings and start the Elmish dispatch loop for the window. 8. Create a WPF app project (using the Visual Studio template called `WPF App (.NET)`). This will be your entry point and contain the XAML views. Add a reference to the F# project, and make the following changes in the `csproj` file: * Currently, the core Elmish logs are only output to the console. If you want a console window for displaying Elmish logs, change `WinExe` to `Exe` and add `true`. * If the project file starts with the now legacy ``, change it to `` * Change the target framework to match the one used in the F# project (e.g. `net5.0-windows`). Make the following changes to `App.xaml.cs` to initialize Elmish when the app starts: ```c# public partial class App : Application { public App() { this.Activated += StartElmish; } private void StartElmish(object sender, EventArgs e) { this.Activated -= StartElmish; Program.main(MainWindow); } } ``` 9. Define your views and bindings in XAML: ```xaml