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)
这里的问题是更新视图组件的代码是重复的。我相信这是因为:
- 在
ListView
对象表达式的 ProcessKey
方法中我无法访问 Tui 的任何外部方法 class (这可能也是因为 F# 编译器仅通过一次( ?))
- 在该方法之外我无法访问
updateView
函数
是否有更好的方法来避免代码重复?我是否使用了错误的模式 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()
我正在寻找将模型更新传播到 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)
这里的问题是更新视图组件的代码是重复的。我相信这是因为:
- 在
ListView
对象表达式的ProcessKey
方法中我无法访问 Tui 的任何外部方法 class (这可能也是因为 F# 编译器仅通过一次( ?)) - 在该方法之外我无法访问
updateView
函数
是否有更好的方法来避免代码重复?我是否使用了错误的模式 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()