elmish / Elmish.WPF

Static WPF views for elmish programs
Other
421 stars 68 forks source link

How to send a message to the Dispatcher from a custom event? #572

Open awaynemd opened 1 year ago

awaynemd commented 1 year ago

This is a repost of a StackOverflow question.

In Elmish.wpf, I have a custom event as a singleton:

type EventMediator private () = let mutable _name = "";

static member val private _instance = lazy EventMediator()
static member Instance = EventMediator._instance.Value

member val private nameChanged = Event<unit>()
member this.NameChanged = this.nameChanged.Publish

member this.Name
    with get() = _name
    and set(value) =
        _name <- value
        this.nameChanged.Trigger()

Once triggered, it is received in a separate module as:

let p = EventMediator.Instance p.NameChanged.Add(fun () -> dispatch RequestAppointmentsMsg ) <--WRONG! where RequestAppointmentsMsg is defined (Elemish.wpf) as

type Msg =
| RequestAppointmentsMsg The call-back to the event is outside of the Update loop.

How can I send the message "RequestAppointmentsMsg" in Elmish.wpf to the dispatcher so it will be acted upon by the Update loop?

Thank you.

Note: the signature for the update loop is:

update (msg:Msg) (m:Registration) : Registration * Cmd = ....

LyndonGingerich commented 1 year ago

I take it that it is pretty important that EventMediator be initialized lazily? Otherwise, of course, you could use an F# module instead of hand-writing a static class.

Once triggered, it is received in a separate module

Where is the separate module in your code structure? The means by which you will send RequestAppointmentsMsg to the dispatcher depends on the location of the event handler. If your WPF code handles the event, make an Elmish.WPF command binding in your view model that returns message RequestAppointmentsMsg, then execute the binding's ICommand from your WPF code. If the event handler isn't accessible to your WPF code but is accessible to your main function (step 7 in the README), you can pass the dispatcher into the class constructor as an argument, then use Elmish.Cmd.ofEffect to connect it to the Elmish loop. But this method is significantly more complicated, so I would need more information to walk you through it.

TysonMN commented 1 year ago

Do not simultaneously cross post: https://stackoverflow.com/q/76547050/741786