Avalonia.FuncUI - How to update ProgressBar value with MVU pattern?

Hi,

I am new to Elm/Elmish/MVU. I am trying to to fetch some data after a button click. How can i update the progressbar while iterating the results?

Is there a way to create a dispatch event without any user interaction? My idea was to propagate the create a function that does the processing for the list head, and then sends the tail to Loading, but there seems to be no way to continue from there. The view is stuck as progressbar (value 1)

Elmish.Program.mkSimple (fun () -> MainView.init) MainView.update MainView.view
 ...
let update (msg: Msg) (state: State) : State =
        match msg with
        | LoadData ->
            match state with
            | Start s ->
                ...
                let deviceList = Api.Load()
                    deviceList
                    |> Array.iteri (fun i device->
                           (
                            // How to increment the progress bar here?
                            ...
                            )
                
                Loaded devices
            | Loading p -> Loading p
            | Loaded (data, getModel) -> Loaded (data, getModel)
 ...
 let rec view (state: State) (dispatch) =
    ...
    let rec view (state: State) (dispatch) =
        match state with
        | Start s ->
            StackPanel.create [
                StackPanel.spacing 8.0
                StackPanel.children [
                        TextBox.create [
                            TextBox.text "Start"
                        ]
                        Button.create [
                            Button.content "Load data from api"
                            Button.onClick (fun _ -> dispatch (LoadData))
                        ]
                ]
            ]
        | Loading progress ->
            StackPanel.create [
                StackPanel.spacing 8.0
                StackPanel.children [
                    ProgressBar.create [
                        ProgressBar.minimum 0.0
                        ProgressBar.maximum 100.0
                        ProgressBar.value progress.PercentageDone
                    ]
                ]
            ]
       ...

You might be interested in this post, which talks about using mkProgram instead of mkSimple and introduces the concept of “Commands.” Some snippets that convince me it’s what you’re looking for:

These commands are, among other things, a method for dispatching or even automating further changes to your model without any user input

However, if you were to build this same program using Elmish’s Program.mkSimple you… wouldn’t be able to do it at all because Program.mkSimple only returns the model from its update function, not any commands.

Ultimately, you need your update function to be able to have some additional side-effects, instead of just returning a single updated State. And that’s what “Commands” are for.

1 Like

The solution was using mkProgram and then passing a subscription as the Cmd (Cmd.ofSub)

let apiLoadSubscription state: Sub<Msg> =
            let sub dispatch =
                 ...
                 Progress p |> dispatch
            sub

...

 let update (msg: Msg) (state: State) : State * Cmd<Msg> =
        match msg with
        | LoadData ->
            match state with
            | Start s ->
                state, Cmd.ofSub (apiLoadSubscription s)
...
1 Like