All Projects → unoplatform → Elmish.Uno

unoplatform / Elmish.Uno

Licence: other
Static UWP views for elmish programs running with the Uno Platform

Programming Languages

F#
602 projects
C#
18002 projects

Projects that are alternatives of or similar to Elmish.Uno

MADE.NET
MADE.NET is a home to all of those bits of code that you know you'll reuse in another project. Making app development easier with .NET.
Stars: ✭ 75 (+226.09%)
Mutual labels:  uwp, uno-platform
dotnet
.NET Community Toolkit is a collection of helpers and APIs that work for all .NET developers and are agnostic of any specific UI platform. The toolkit is maintained and published by Microsoft, and part of the .NET Foundation.
Stars: ✭ 865 (+3660.87%)
Mutual labels:  uwp, uno-platform
WinDev-Utility
A utility for windows developers
Stars: ✭ 17 (-26.09%)
Mutual labels:  uwp, uno-platform
Uno.Themes
This library is designed to help you use the material design system with the Uno Platform
Stars: ✭ 112 (+386.96%)
Mutual labels:  uwp, uno-platform
uno.toolkit.ui
A set of custom controls for the WinUI and the Uno Platform not offered out of the box by WinUI, such as Card, TabBar, NavigationBar, etc.
Stars: ✭ 45 (+95.65%)
Mutual labels:  uwp, uno-platform
Uno
Build Mobile, Desktop and WebAssembly apps with C# and XAML. Today. Open source and professionally supported.
Stars: ✭ 6,029 (+26113.04%)
Mutual labels:  uwp, uno-platform
xavtool
Xplat Automating Version Tool
Stars: ✭ 33 (+43.48%)
Mutual labels:  uwp
APK-Installer
An Android Application Installer for Windows
Stars: ✭ 1,076 (+4578.26%)
Mutual labels:  uwp
AsteroidsWasm
Collection of applications based on a single C# .NET Standard project running in: Blazor Client (WebAssembly), Blazor Server, Electron, WPF, WinForms, Xamarin
Stars: ✭ 136 (+491.3%)
Mutual labels:  uwp
parquet-viewer-uwp
Viewer for Apache Parquet files for Windows 10
Stars: ✭ 30 (+30.43%)
Mutual labels:  uwp
UltraFaceDotNet
C# version of Ultra-Light-Fast-Generic-Face-Detector-1MB for Windows, MacOS, Linux, iOS and Android
Stars: ✭ 56 (+143.48%)
Mutual labels:  uwp
Bili.Uwp
适用于新系统UI的哔哩
Stars: ✭ 7,038 (+30500%)
Mutual labels:  uwp
DebounceMonitoring
📑 Add debounce logic for any method in a single line.
Stars: ✭ 44 (+91.3%)
Mutual labels:  uwp
leto
Leto: Realtime Application Stack [Angualr2, Rethinkdb/Horizon, ExpressJS] Web | Mobile | Desktop
Stars: ✭ 21 (-8.7%)
Mutual labels:  uwp
Chessman
Chess analysis Universal Windows 10 application.
Stars: ✭ 14 (-39.13%)
Mutual labels:  uwp
MorseCodeReceiver-UWP
💡 An UWP app which can translate the light sensor data into Morse code on mobile device.
Stars: ✭ 14 (-39.13%)
Mutual labels:  uwp
XamlIslands
Repository with several XAML Islands v1 samples (Win32, WPF, and WinForms) to demonstrate how to use it.
Stars: ✭ 47 (+104.35%)
Mutual labels:  uwp
elmish-getting-started
A simple and minimalistic template to easily get up and running with Elmish and Fable
Stars: ✭ 22 (-4.35%)
Mutual labels:  elmish
UWPGmaps.SDK
Unofficial Google Map SDK for Universal Windows Platform (UWP)
Stars: ✭ 16 (-30.43%)
Mutual labels:  uwp
Rocksmith2014.NET
F# (with some C#) libraries for creating Rocksmith 2014 custom DLC.
Stars: ✭ 26 (+13.04%)
Mutual labels:  elmish

WPF done the Elmish Way

NuGet version NuGet downloads Build status

Never write a ViewModel class again!

This library uses Elmish, an Elm architecture implemented in F#, to build WPF applications. Elmish was originally written for Fable applications, however it was trimmed and packaged for .NET as well.

Recommended resources

  • The Elmish docs site explains the general Elm architecture and principles.
  • The Elmish.WPF samples provide many concrete usage examples.
  • The official Elm guide 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.

Getting started with Elmish.WPF

See the SingleCounter sample for a very simple app. The central points are:

  1. Create an F# Console Application (you can create a Windows application, but the core Elmish logs are currently only written to the console).

  2. Add References to PresentationCore, PresentationFramework, and WindowsBase.

  3. Add NuGet reference to package Elmish.WPF.

  4. Define the model that describes your app’s state and a function that initializes it:

    type Model =
      { Count: int
        StepSize: int }
    
    let init () =
      { Count = 0
        StepSize = 1 }
  5. Define the various messages that can change your model:

    type Msg =
      | Increment
      | Decrement
      | SetStepSize of int
  6. Define an update function that takes a message and a model and returns an updated model:

    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 }
  7. Define the “view” function using the Bindings module. This is the central public API of Elmish.WPF. Normally 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 simply sets up bindings that XAML-defined views can use. Therefore, let’s call it bindings instead of view. In order to be compatible with Elmish it needs to have the same signature, but in many (most?) cases the model and dispatch parameters will be unused:

    open Elmish.WPF
    
    let bindings model dispatch =
      [
        "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.

  8. Create a WPF user control library project to hold you XAML files, add a reference to this project from your Elmish project, and define your views and bindings in XAML:

    <Window
        x:Class="MyNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
      <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding CounterValue}" />
        <Button Command="{Binding Decrement}" Content="-" />
        <Button Command="{Binding Increment}" Content="+" />
        <TextBlock Text="{Binding StepSize}" />
        <Slider Value="{Binding StepSize}" TickFrequency="1" Minimum="1" Maximum="10" />
      </StackPanel>
    </Window>
  9. Add the entry point to your console project:

    open System
    open Elmish
    
    [<EntryPoint; STAThread>]
    let main argv =
      Program.mkSimple init update bindings
      |> Program.runWindow (MainWindow())

    Program.runWindow will instantiate an Application and set the window’s DataContext to the bindings you defined.

  10. Profit! :)

For more complicated examples and other Binding functions, see the samples.

FAQ

Do I have to use the project structure outlined above?

Not at all. The above example, as well as the samples, keep everything in a single project for simplicity (the samples have the XAML definitions in separate projects for technical reasons). For more complex apps, you might want to consider a more clear separation of UI and core logic. An example would be the following structure:

  • A core library containing the model definitions and update functions. This library can include a reference to Elmish (e.g. for the Cmd module helpers), but not to Elmish.WPF, which depends on certain WPF UI assemblies and has a UI-centred API (the Binding module). This will ensure your core logic (such as the update function) is free from any UI concerns, and allow you to re-use the core library should you want to port your app to another Elmish-based solution (e.g. using Fable).
  • An entry point project that contains the bindings (or view) function and the call to Program.runWindow. This project would reference the core library and Elmish.WPF.
  • A view project containing the XAML-related stuff (windows, user controls, behaviors, etc.). This could also be part of the entry point project, but if you’re using the new project format (like the samples in this repo), this might not work properly until .NET Standard 3.0.

Can I instantiate Application myself?

Yes, just do it before calling Program.runWindow and it will automatically be used. You might need this if you have application-wide resources in a ResourceDictionary, which might require you to instantiate the application before instantiating the main window you pass to Program.runWindow.

Can I use design-time view models?

Yes. You need to structure your code so you have a place, e.g. a file, that satisfies the following requirements:

  • Must be able to instantiate a model and the associated bindings
  • Must be reachable by the XAML views

There, open Elmish.WPF.Utilities and use ViewModel.designInstance to create a view model instance that your XAML can use at design-time:

module Foo.DesignViewModels
open Elmish.WPF.Utilities
let myVm = ViewModel.designInstance myModel myBindings

Then use the following attributes wherever you need a design VM:

<Window
    ...
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vm="clr-namespace:Foo;assembly=Foo"
    mc:Ignorable="d"
    d:DataContext="{x:Static vm:DesignViewModels.myVm}">

Project code must of course be enabled in the XAML designer for this to work.

Can I open new windows/dialogs?

The short version: Yes, but depending on the use-case, this may not play well with the Elmish architecture, and it is likely conceptually and architecturally clearer to stick with some kind of dialog in the main window, using bindings to control its visibility.

The long version:

You can easily open modeless windows (using window.Show()) in command and set the binding context of the new window to the binding context of the main window. The NewWindow sample demonstrates this. It is then, from Elmish’s point of view, absolutely no difference between the windows; the bindings and message dispatches work exactly the same as if you had used multiple user controls in a single window, and you may close the new window without Elmish being affected by it.

Note that the NewWindow sample (like the other samples) keep a very simple project structure where the views are directly accessible in the core logic, which allows for direct instantiation of new windows in the update function (or the commands it returns). If you want a clearer separation between UI and core logic as previously described, you would need to write some kind of navigation service abstraction and use inversion of control (such as dependency injection) to allow the core project to instantiate the new window indirectly using the navigation service without needing to reference the UI layer directly. Such architectural patterns of course go very much against the grain of Elmish and functional architecture in general.

While modeless windows are possible, if not necessarily pleasant or idiomatic, you can not use the same method to open modal windows (using window.ShowDialog()). This will block the Elmish update loop, and all messages will be queued and only processed when the modal window is closed.

Windows that semantically produce a result, even if you implement them as modeless, can be more difficult. An general example might be a window containing a data entry form used to create a business entity. In these cases, a “Submit” button may need to both dispatch a message containing the window’s result (done via Binding.cmd or similar), as well as close the window. This can be problematic, or at least cumbersome, when there is logic determining what actually happens when the “Submit” button is clicked (send the result, display validation errors, etc.). For more on this, see the discussion in #24.

The recommended approach is to stick to what is available via bindings in a single window. In the case of new windows, this means instead using in-window dialogs, similar to how most SPAs (single-page applications) created with Elm or Elmish would behave. This allows the UI to be a simple function of your model, which is a central point of the Elm architecture (whereas opening and closing windows are events that do not easily derive from any model state). The SubModelOpt sample provides a very simple example of custom dialogs, and this method also works great with libraries with ready-made MVVM-friendly dialogs, e.g. those in Material Design In XAML Toolkit.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].