6 people like it.

Example of Elm-like immutable MVVM

An example of a simple ViewModel for WPF inspired by the "immutable" Elm Architecture - http://elm-lang.org/. It is just an proof of concept. See the library code and a few working examples at https://github.com/Zdenek-Pavlis/impF

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
56: 
57: 
58: 
59: 
60: 
61: 
62: 
63: 
64: 
open impF.VmBase


module Person = 
    type Model = 
        { FirstName : string
        ; LastName  : string
        ; IsSwapped : bool
        } 
        with
        member x.FullName = 
            sprintf "%s %s" x.FirstName x.LastName
        member x.IsNotSwapped = 
            not x.IsSwapped

    type Msg = 
        | First of string
        | Last of string
        | Swap
        | SwapBack
 
    let init =
        { FirstName = ""
        ; LastName = ""
        ; IsSwapped = false
        }

    let update msg state = 
        let swap () = 
            { IsSwapped = not state.IsSwapped
            ; FirstName = state.LastName
            ; LastName = state.FirstName 
            }

        match msg with 
        | First s -> 
            { state with FirstName = s }
        | Last s -> 
            { state with LastName = s }
        | Swap -> 
            swap()
        | SwapBack -> 
            swap()


 type PersonVm(p) =
    let sm = 
        stateManager Person.update p

    member val FirstName = 
        sm.Field Person.Msg.First (fun m -> m.FirstName) 
    member val LastName = 
        sm.Field Person.Msg.Last (fun m -> m.LastName)
    member val FullName = 
        sm.RoField (fun m -> m.FullName)
    member val SwapCommand = 
        sm.Command Person.Msg.Swap (fun m -> m.IsNotSwapped)
    member val SwapBackCommand = 
        sm.Command Person.Msg.SwapBack (fun m -> m.IsSwapped)


module VmFactory =
    let newVm () = 
        createRootVm PersonVm Person.init
namespace impF
module VmBase

from impF
type Model =
  {FirstName: string;
   LastName: string;
   IsSwapped: bool;}
  member FullName : string
  member IsNotSwapped : bool

Full name: Script.Person.Model
Model.FirstName: string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string
Model.LastName: string
Model.IsSwapped: bool
type bool = System.Boolean

Full name: Microsoft.FSharp.Core.bool
val x : Model
member Model.FullName : string

Full name: Script.Person.Model.FullName
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
member Model.IsNotSwapped : bool

Full name: Script.Person.Model.IsNotSwapped
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not
type Msg =
  | First of string
  | Last of string
  | Swap
  | SwapBack

Full name: Script.Person.Msg
union case Msg.First: string -> Msg
union case Msg.Last: string -> Msg
union case Msg.Swap: Msg
union case Msg.SwapBack: Msg
val init : Model

Full name: Script.Person.init
val update : msg:Msg -> state:Model -> Model

Full name: Script.Person.update
val msg : Msg
val state : Model
val swap : (unit -> Model)
val s : string
Multiple items
type PersonVm =
  new : p:VmStateManagerParams<Model> -> PersonVm
  member FirstName : Field<string>
  member FullName : ReadOnlyField<string>
  member LastName : Field<string>
  member SwapBackCommand : ImmutableCommand
  member SwapCommand : ImmutableCommand

Full name: Script.PersonVm

--------------------
new : p:VmStateManagerParams<Person.Model> -> PersonVm
val p : VmStateManagerParams<Person.Model>
val sm : VmStateManager<Person.Msg,Person.Model>
val stateManager : update:('a -> 'state -> 'state) -> p:VmStateManagerParams<'state> -> VmStateManager<'a,'state> (requires equality)

Full name: impF.VmBase.stateManager
module Person

from Script
val update : msg:Person.Msg -> state:Person.Model -> Person.Model

Full name: Script.Person.update
member IVmStateManager.Field : msgBuilder:('fieldState -> 'msg) -> fieldStateSelector:('state -> 'fieldState) -> Field<'fieldState> (requires equality and equality)
union case Person.Msg.First: string -> Person.Msg
val m : Person.Model
Person.Model.FirstName: string
union case Person.Msg.Last: string -> Person.Msg
Person.Model.LastName: string
member IVmStateManager.RoField : fieldStateSelector:('state -> 'fieldState) -> ReadOnlyField<'fieldState> (requires equality and equality)
property Person.Model.FullName: string
member IVmStateManager.Command : msg:'msg -> canExecuteSelector:('state -> bool) -> ImmutableCommand (requires equality)
union case Person.Msg.Swap: Person.Msg
property Person.Model.IsNotSwapped: bool
union case Person.Msg.SwapBack: Person.Msg
Person.Model.IsSwapped: bool
module VmFactory

from Script
val newVm : unit -> PersonVm

Full name: Script.VmFactory.newVm
val createRootVm : factory:(VmStateManagerParams<'vmState> -> 'vm) -> init:'vmState -> 'vm

Full name: impF.VmBase.createRootVm
val init : Person.Model

Full name: Script.Person.init

More information

Link:http://fssnip.net/7QK
Posted:7 years ago
Author:Zdenek Pavlis
Tags: mvvm , wpf