Elmish.WPF如何实现集合到多窗口实例的绑定?
Elmish.WPF 绑定集合模型实现多实例子窗口方案
核心思路
Elmish.WPF 没有直接提供subModelWinParam这类带参数的子窗口绑定方法,但可以通过跟踪每个子窗口的打开状态 + 为集合中每个元素生成独立的子窗口绑定来实现需求:通过按钮参数指定索引,打开对应集合元素绑定的子窗口。
1. 调整模型与消息类型
首先扩展模型,新增子窗口打开状态集合;同时更新消息类型,加入带索引的窗口控制与子消息传递:
// App.fs type Model = { Window1Data: Window1Model list // 存储所有Window1的模型集合 Window1IsOpen: bool list // 对应每个Window1的打开状态 // 保留原有其他字段... } type Msg = | Window1Show of int // 带索引的打开窗口命令 | Window1Close of int // 带索引的关闭窗口命令 | Window1SetInput of int * Window1.Msg // 带索引的子窗口消息(关联对应模型) // 保留原有其他消息...
2. 初始化模型
确保初始状态下,窗口打开状态集合与模型集合长度一致:
// App.fs let init () = // 初始化Window1Model集合,示例创建2个实例 let initialWindow1Data = [ Window1.init (); Window1.init () ] // 初始化所有窗口为关闭状态 let initialWindow1IsOpen = initialWindow1Data |> List.map (fun _ -> false) { Window1Data = initialWindow1Data Window1IsOpen = initialWindow1IsOpen // 初始化其他原有字段... }, Cmd.none
3. 更新消息处理逻辑
在update函数中处理新增的消息,实现窗口状态切换与子模型更新:
// App.fs let update (msg: Msg) (model: Model) = match msg with | Window1Show idx -> // 校验索引合法性,切换对应窗口的打开状态 if idx >= 0 && idx < model.Window1IsOpen.Length then let newIsOpen = model.Window1IsOpen |> List.mapi (fun i b -> if i = idx then true else b) { model with Window1IsOpen = newIsOpen }, Cmd.none else model, Cmd.none | Window1Close idx -> // 校验索引合法性,关闭对应窗口 if idx >= 0 && idx < model.Window1IsOpen.Length then let newIsOpen = model.Window1IsOpen |> List.mapi (fun i b -> if i = idx then false else b) { model with Window1IsOpen = newIsOpen }, Cmd.none else model, Cmd.none | Window1SetInput (idx, subMsg) -> // 校验索引合法性,更新对应子模型 if idx >= 0 && idx < model.Window1Data.Length then let newWindow1Data = model.Window1Data |> List.mapi (fun i m -> if i = idx then Window1.update subMsg m else m) { model with Window1Data = newWindow1Data }, Cmd.none else model, Cmd.none // 保留原有其他消息处理逻辑...
4. 实现多实例子窗口绑定
通过循环为集合中每个元素生成独立的subModelWin绑定,关联对应索引的模型与窗口状态:
// App.fs let bindings (createWindow1: unit -> #Window) (createWindow2: unit -> #Window) () = // 为每个Window1实例生成专属绑定 let generateWindow1Bindings model = model.Window1Data |> List.mapi (fun idx _ -> // 获取对应索引的子模型 let getSubModel (m: Model) = m.Window1Data[idx] // 获取对应索引的窗口打开状态 let getIsOpen (m: Model) = m.Window1IsOpen[idx] // 更新对应索引的窗口打开状态 let setIsOpen isOpen (m: Model) = m.Window1IsOpen |> List.mapi (fun i b -> if i = idx then isOpen else b) |> fun newIsOpen -> { m with Window1IsOpen = newIsOpen } // 映射子窗口消息,关联当前索引 let subBindings = Window1.bindings () |> Bindings.mapMsg (function // 将子窗口的关闭消息直接映射为主窗口的Window1Close命令 | Window1.Msg.Close -> Window1Close idx // 其他子消息带上索引传递给主模型处理 | subMsg -> Window1SetInput (idx, subMsg)) // 生成该索引窗口的绑定条目 $"Window1_{idx}" |> Binding.subModelWin getSubModel getIsOpen setIsOpen subBindings createWindow1 ) // 主绑定列表 + 所有Window1实例的绑定 fun model -> [ "Window1Show" |> Binding.cmdParam (int >> Window1Show) // 保留原有其他绑定... ] @ generateWindow1Bindings model
5. 子窗口绑定调整
确保子窗口(Window1)的关闭命令能触发对应消息,示例如下:
// Window1.fs type Msg = | Close // 保留原有其他子消息... let bindings () = [ // 绑定关闭按钮命令 "Close" |> Binding.cmd (fun () -> Close) // 保留原有其他子绑定... ]
工作流程说明
- 点击主窗口带参数的按钮时,发送
Window1Show idx消息,update函数将对应索引的Window1IsOpen设为true - Elmish.WPF通过
subModelWin检测到状态变化,自动创建并显示对应索引绑定的Window1实例 - 子窗口操作时,消息会带上索引传递给主模型,更新对应位置的
Window1Data - 点击子窗口关闭按钮时,发送
Window1Close idx消息,update函数将对应索引的Window1IsOpen设为false,Elmish.WPF自动关闭窗口
内容的提问来源于stack exchange,提问作者Franco Tiveron
相关产品推荐
相关产品推荐

