Skip to content

Commit

Permalink
Merge pull request elmish#374 from TysonMN/fix_373_backwards_text
Browse files Browse the repository at this point in the history
synchronously dispatch msgs from the UI and asynchronously from commands
  • Loading branch information
TysonMN authored Mar 12, 2021
2 parents 167bdb1 + b5482e4 commit 0e56d68
Showing 1 changed file with 24 additions and 4 deletions.
28 changes: 24 additions & 4 deletions src/Elmish.WPF/WpfProgram.fs
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,36 @@ module WpfProgram =
let bindingsLogger = program.LoggerFactory.CreateLogger("Elmish.WPF.Bindings")
let performanceLogger = program.LoggerFactory.CreateLogger("Elmish.WPF.Performance")

let setState model dispatch =
(*
* Capture the dispatch function before wrapping it with Dispatcher.InvokeAsync
* so that the UI can sychrononously dispatch messages.
* In additional to being slightly more efficient,
* it also helps keep WPF in the correct state.
* https://github.com/elmish/Elmish.WPF/issues/371
* https://github.com/elmish/Elmish.WPF/issues/373
*
* This is definitely a hack.
* Maybe something with Elmish can change so this hack can be avoided.
*)
let mutable dispatch = Unchecked.defaultof<Dispatch<'msg>>

let setState model _ =
match viewModel with
| None ->
let vm = ViewModel<'model, 'msg>(model, dispatch, program.Bindings, program.PerformanceLogThreshold, "main", bindingsLogger, performanceLogger)
let uiDispatch msg = element.Dispatcher.Invoke(fun () -> dispatch msg)
let vm = ViewModel<'model, 'msg>(model, uiDispatch, program.Bindings, program.PerformanceLogThreshold, "main", bindingsLogger, performanceLogger)
element.DataContext <- vm
viewModel <- Some vm
| Some vm ->
vm.UpdateModel model

let uiDispatch (innerDispatch: Dispatch<'msg>) : Dispatch<'msg> =
let cmdDispatch (innerDispatch: Dispatch<'msg>) : Dispatch<'msg> =
dispatch <- innerDispatch
(*
* Have commands asychrononously dispatch messages.
* This avoids race conditions like can occur when shutting down.
* https://github.com/elmish/Elmish.WPF/issues/353
*)
fun msg -> element.Dispatcher.InvokeAsync(fun () -> innerDispatch msg) |> ignore

let logMsgAndModel (msg: 'msg) (model: 'model) =
Expand All @@ -79,7 +99,7 @@ module WpfProgram =
|> if updateLogger.IsEnabled LogLevel.Trace then Program.withTrace logMsgAndModel else id
|> Program.withErrorHandler logError
|> Program.withSetState setState
|> Program.withSyncDispatch uiDispatch
|> Program.withSyncDispatch cmdDispatch
|> Program.run


Expand Down

0 comments on commit 0e56d68

Please sign in to comment.