如何在Elmish.WPF/Elmish中从自定义事件向调度器发送消息?
Elmish.WPF 中从外部事件向Update循环发送消息的解决方案
问题场景
你定义了一个单例事件中介类:
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()
尝试在外部模块中订阅事件并发送Elmish消息时,因回调处于Update循环外,直接调用dispatch无效:
let p = EventMediator.Instance p.NameChanged.Add(fun () -> dispatch RequestAppointmentsMsg ) // 无效
相关定义:
type Msg = | RequestAppointmentsMsg
Update循环签名:
update (msg:Msg) (m:Registration) : Registration * Cmd<Msg> = ....
解决方案
方法1:将Dispatch函数注入到事件中介
修改单例类,添加存储dispatch函数的字段与设置方法,在Elmish程序启动时传入有效dispatch:
- 更新
EventMediator:
type EventMediator private () = let mutable _name = "" let mutable _dispatch : (Msg -> unit) option = None 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 // 添加设置dispatch的方法 member this.SetDispatch(dispatch) = _dispatch <- Some dispatch member this.Name with get() = _name and set(value) = _name <- value this.nameChanged.Trigger() // 可直接在这里触发消息,无需外部订阅 match _dispatch with | Some d -> d RequestAppointmentsMsg | None -> ()
- 在Elmish程序初始化时传入dispatch:
Program.mkProgram init update view |> Program.withWpfConfig config |> Program.runWith (fun dispatch -> EventMediator.Instance.SetDispatch dispatch )
若仍需外部订阅事件,可直接使用存储的dispatch:
let p = EventMediator.Instance p.NameChanged.Add(fun () -> match p.Dispatch with | Some d -> d RequestAppointmentsMsg | None -> () )
方法2:用Elmish的Cmd订阅外部事件
利用Elmish的Cmd.ofSub,在初始化或消息处理逻辑中订阅外部事件,确保回调处于Elmish上下文内,可直接发送消息:
- 在
init函数中添加订阅逻辑:
let init () : Registration * Cmd<Msg> = let initialModel = { ... } // 封装订阅事件的Cmd let subscribeEvent = Cmd.ofSub (fun dispatch -> let p = EventMediator.Instance p.NameChanged.Add(fun () -> dispatch RequestAppointmentsMsg) ) initialModel, subscribeEvent
这种方式更贴合Elmish架构设计,所有外部事件订阅通过Cmd统一管理,避免全局状态依赖。
内容的提问来源于stack exchange,提问作者Alan Wayne
相关产品推荐
相关产品推荐

