Closed Palsskv closed 5 months ago
Try Program.runWithAvaloniaSyncDispatch
Thanks, @JordanMarr. It works now.
Maybe it makes sense to set up an exception handler somewhere in the FuncUI stack, as a temporary measure? Make it reraise with more detailed instructions on setting up dispatcher synchronization.
I've just started using this library, so my understanding of its design is practically nil :). From a user perspective this looks like a bug though, because the ofError
function only returns the message without calling into dispatch.
Not sure if this is connected, but the happy path messages don't get processed.
Full code:
let update (msg: AppMsg) (appModel: AppModel) =
match msg with
| ParseFile uri ->
let processing =
fun _ ->
async {
let! rows = Parser.AsyncLoad(uri.LocalPath) // the parser throws for invalid input
if (rows.Rows |> Seq.isEmpty |> not) then
return ItemsParsed(rows.Rows |> Seq.toArray)
else
return FailParse "No rows found in file"
}
{ appModel with
State = InputFileSelected uri}
, (Elmish.Cmd.OfAsyncImmediate.attempt processing () (fun ex -> FailParse ex.Message)
type AppMsg =
| ParseFile of Uri
| FailParse of string
| ItemsParsed of Parser.Row array
| FileDragDropMsg of FileDragDrop.FileDragDropMsg
I have tracing enabled with Program.withTrace (fun msg model subs -> printfn $"msg: {msg} {model} {subs}")
and the messages don't get logged or otherwise processed.
Ushering async data back to the main UI thread has been a part of UI development for a long time. But I get your point.
I think Program.runWithAvaloniaSyncDispatch ()
should be used by default as there really is no drawback.
And maybe we should consider making that call obsolete and instead introducing:
Program.runFuncUI ()
Not sure if this is connected, but the happy path messages don't get processed.
You should be able to just use Cmd.OfAsync
instead of Cmd.OfAsyncImmediate
.
Stylistically, it would look better if you:
open Elmish
instead of Elmish.Cmd
everywhereFailParse
take an Exception
instead of a string
, and then could you just have:
, Cmd.OfAsync.attempt processing () FailParse
For anyone reading this, the happy path issue was unrelated. either
is what I should have used instead of attempt
. attempt
accepts functions with returns, but does not dispatch the successful, non-exception result.
If I get more time to spend on UI work, I could look into patching attempt
to accept 'a -> unit
functions only and submit a PR. @JordanMarr let me know if this sits well with the intended architecture.
Glad you got it working. 😎 I don’t personally think there is a need to change any of the built-in Elmish handlers in this library. It would be better to propose any changes in the Elmish repository itself.
There seems to be an issue with async workloads that are not scheduled on the UI thread.
The async workload is executed on the ThreadPool
All follow-up view & update code is then run from the TP Thread which ends up throwing:
Running with
Elmish.Cmd.OfAsyncImmediate.attempt
fixes this, but puts the async code on the main thread.