heoo.lib 1.3.1

dotnet add package heoo.lib --version 1.3.1
NuGet\Install-Package heoo.lib -Version 1.3.1
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="heoo.lib" Version="1.3.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add heoo.lib --version 1.3.1
#r "nuget: heoo.lib, 1.3.1"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install heoo.lib as a Cake Addin
#addin nuget:?package=heoo.lib&version=1.3.1

// Install heoo.lib as a Cake Tool
#tool nuget:?package=heoo.lib&version=1.3.1

half-elmish-oo

I want to create elmish program loops (message processing loops) with a simple callback.

Example

Step1 - Design your program

open heoo.lib
open System

//Elmish programs need a model a message and update function.

type Model = { Count: int; SomeText:string }
type Message = 
    | Increase 
    | Decrease
    | Reset
    | SetText of string

let Update  (model:Model) (msg:Message) =
    match msg with
    | Increase -> { model with Count = model.Count + 1 }
    | Decrease -> { model with Count = model.Count - 1 }
    | Reset -> { model with Count = 0 }
    | SetText text -> { model with SomeText = text }
   

Step2 - Create your viewmodel

type MyVm(initialModel,messageCallback) =
    inherit ViewModelBase.T<Model>(initialModel)
    
    //Remember that this is async.
    //Wait for InotifyPropertyChanged until getter is properly updated.
    member this.GetSetSomeText
        with get() =
            this.getPropertyError(
                fun m ->
                    match m.SomeText with
                    | "" -> "SomeText cannot be empty"
                    | _ -> ""
                    )//empty string is no error
            this.getPropertyValue(fun m -> m.SomeText)
        and set v = v |> SetText |> messageCallback 
    
    member this.GetCounter
        with get() = this.getPropertyValue(fun m -> m.Count)
        
    member this.IncreaseCmd = 
        CommandBase.AlwaysExecutableCommand(fun _ -> messageCallback Increase)
        
    member this.DecreaseCmd = 
        CommandBase.AlwaysExecutableCommand(fun _ -> messageCallback Decrease)
        
    member this.ResetCmd =
           let canExecute = fun _ m -> m.Count <> 0 //commandParameter -> model -> bool
           let execute = fun _ -> messageCallback Reset //commandParameter -> unit
           this.getCommandBaseT(canExecute,execute)
           
    member this.GetAllErrorMessages
        //ignore the keys (propertynames) and just get the values in an array
        with get():string array = this.getPropertyValue(
            fun model ->
                //Errors are stored as key,value pairs.
                //Where value is a function that returns a string from given model.
                this.GetErrorsArray()
                |> Array.map(fun (_,errorFunc) -> errorFunc model)
            )    

Step3 - Instantiate your program loop and viewmodel


let initialModel = { Count = 0; SomeText = "Hello World" }
let program = new ElmishProgramAsync.T<Model,Message>(initialModel,Update)
//WARNING!, once you call (IDisposable)Dispose() on the program loop, you can't use it anymore.
//like this: program.AsIDisposable().Dispose()
let viewModelInstance = MyVm(initialModel,program.PostMessage)

Step3.1 - wire OnModelUpdated to viewmodel

//Remember to wire your programs OnModelUpdated action to your viewmodel
//It might be a good idea to not write this here and move it into your gui application instead.
program.OnModelUpdated <- 
    Action<Model>(
        fun m ->
          //if this is a gui application, thread synchronization is (usually) needed.
          //This might be a good place for it to happen.
          //...
          //example: Dispatcher.Invoke(viewMModelInstance.updateModel m)
          viewModelInstance.updateModel m
    )
    |> Some

Step4 - Consume your viewmodel

Consume your viewmodel in your application (wpf, Winforms, Avalonia, MAUI.net,Uno, Unity3D etc) As you would with any other INotifyPropertyChanged,INotifyDataErrorInfo, IDataErrorInfo, ICommand implementation.

Additional comments

It should be no problem to create more elmishprograms to avoid the whole monolithic approach. It's also possible to have multiple viewmodels from one program. I'm trying to leave the door open for more advanced scenarios.
Where you as a consumer is in control.

Don't mistake my absence for abandonment.
This library is complete and stable and will stand the test of time.
heoo.lib isnt about running fast or optimizing, its only a layer between logic and ui. I use it in my own products which are planned to run for 10+ years.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.3.1 258 3/1/2023
1.3.0 219 2/15/2023
1.2.5 237 2/7/2023
1.2.4 469 10/12/2022
1.2.3 433 10/6/2022
1.2.2 431 10/5/2022
1.2.1 452 9/27/2022
1.2.0 457 9/25/2022
1.1.3-rc 264 9/15/2022
1.1.2-rc 483 9/14/2022
1.1.1-rc 116 9/13/2022
1.1.0-rc 134 9/13/2022
1.0.1-rc 115 9/6/2022
1.0.0-rc 113 9/5/2022

Optional parameter added for ElmishProgramAsync constructor. It is now possible to send updated model between messages or after all messages have been processed. Standard and recommended is AfterAllMessages, at least when viewmodels are the consumers.