F# 中的 GUI 更新模式

GUI update patterns in F#

我正在寻找将模型更新传播到 GUI 的最佳方式,使用 "classic"(如:非反应性功能)GUI 工具包:Terminal.GUI。目前我有这个代码(简化):

    type Tui(state: StateManager) =
        let state = state

        let window = Window(bla bla bla)

        let lblPath = Label(bla bla bla)

        let lstView =
            { new ListView(bla bla bla) with
                  member this.ProcessKey(k: KeyEvent) =

                      let updateViews() =
                          Application.MainLoop.Invoke(fun () ->
                            this.SetSource model.CurrentState.LstData
                            lblPath.Text <- ustr model.CurrentState.CurrPath)

                      match k.Key with
                      | Key.CursorRight -> 
                            state.changeTheState()
                            updateViews()
                            true
                      | _ -> true }
        do
            Application.Init()
            // add all GUI components: window.add(lblPath), etc
            Application.Run()
            // XXX repetition of updateViews() above!
            Application.MainLoop.Invoke(fun () ->
                lstView.SetSource model.CurrentState.LstData
                lblPath.Text <- ustr model.CurrentState.CurrPath)

这里的问题是更新视图组件的代码是重复的。我相信这是因为:

是否有更好的方法来避免代码重复?我是否使用了错误的模式 GUI 更新模式?

(完整代码为here)

当然,它不需要太复杂 - 重构您的更新以仅接受一个列表视图参数:

let updateViews (lstView: ListView) =
      Application.MainLoop.Invoke(fun () ->
          lstView.SetSource state.CurrentState.LstData
          ...
      )

在成员定义中,调用:

updateViews(this)

以下,您可以使用updateViews lstView

当您使用对象表达式时,表达式的类型将成为您在 new <type> 中指定的类型,因此您在内部进行的任何类型扩充都不会在外部进行。对于更面向对象的方法,声明一个中间类型:

[<AbstractClass>] 
type UpdateableList() = 
    inherit ListView([||]) 
    abstract member Update: unit -> unit

实施您的更新逻辑:

  { new UpdateableList(X = Pos.At(0), Y = Pos.At(2), ...) with
            member this.Update() =
                ...

并且在您的设置中,您可以访问 public 方法:

lstView.Update()