假设我有一个同时具有2个VID形式的模型/控制器。如果Rebol不支持自定义事件,我将如何更新指向同一模型的2个视图?
答案 0 :(得分:4)
我继续前进并乐于实现属性编辑器MVC。
此示例允许您直接从GUI动态创建模型和视图,因此非常适合显示系统的运行。
当多个视图编辑相同的数据时,您会看到它们保持同步。多个模型可能各有多个视图。
这只是一个例子,展示了在REBOL中构建MVC模式是多么容易。 REBOL中的许多结构在精神上已经是MVC,即使它们没有明确地以这样的方式进行营销。
rebol [
title: "MVC pattern example"
purpose: {
shows an example of a raw MVC pattern in REBOL
the views can create new models and new views, showing interaction
between separate models, views and the controler.
}
]
model!: context [
data: none
views: []
modify: func [label value][
set in data label value
]
propagate: func [
/only label
/local view
][
foreach view views [
either only [
view/refresh/only label
][
view/refresh
]
]
]
]
view!: context [
controller: none ; our controller
model: none ; our model
label: none ; what label in data does this view manipulate?
gui: [
across
space 2x10
style separator box 275x3 edge [size: 1x1 effect: 'ibevel color: (white * .75)]
]
lbl: none ; gui face
fld: none ; gui face
refresh: func [/only label][
; GENERATE the gui if its not been built for this view yet.
if block? gui [
gui: copy/deep gui
; add a button for each item of data in the model, clicking on them changes
; what the field edits.
foreach item words-of model/data [
append gui compose/deep bind/copy [
btn (to-string item) [
print "^/---"
label: (to-lit-word item)
probe label
refresh
]
] self
]
; we must bind because the block is being used in new objects created dynamically.
; if we don't bind the blocks, they stay bound to the class... important detail.
append gui copy/deep bind/copy [
return
separator
return
lbl: h1 200 (to-string label)
return
fld: field [controller/modify model label face/text]
btn "randomize" [controller/randomize model label]
return
pad 0x10
separator
return
pad 160x0
btn "new view" [controller/new-view (model)]
btn "new model" [controller/new-model]
btn "close" [unview/only gui]
] self
gui: view/new layout gui
]
; refresh the gui, when its already built (including on first view)
if any [
none? label
label = self/label
] [
probe model/data
probe self/label
fld/text: copy get in model/data self/label
lbl/text: copy to-string self/label
show fld
show lbl
]
]
]
controller!: context [
models: []
; this just describes how the models should be built,
; it could be a hard-coded in new-model()
model-data: [sid: "0" name: "unknown" occupation: "unknown"]
new-model: func [/local model view prev-model prev-view][
unless empty? models [prev-model: last models]
append models model: make model! [data: context model-data ]
view: new-view model
if prev-model [
; tweak window position which is a bit screwed up in rebol
prev-view: last prev-model/views
view/gui/offset/x: view/gui/offset/x + system/view/no-resize-border/x
view/gui/offset/y: prev-view/gui/offset/y + prev-view/gui/size/y + system/view/no-resize-border/y 8
show view/gui
]
model
]
new-view: func [model /local view prev-view][
probe model/data
if not empty? model/views [
probe length? model/views
prev-view: last model/views
]
append model/views view: make view! compose [
model: (model)
label: (to-lit-word first words-of model/data)
controller: (self) ; here self is the controller, since we are composing
; the value within a controller function
]
view/refresh
if prev-view [
; tweak window position which is a bit screwed up in rebol
view/gui/offset/x: prev-view/gui/offset/x + prev-view/gui/size/x + system/view/no-resize-border/x
view/gui/offset/y: prev-view/gui/offset/y - system/view/title-size/y - system/view/no-resize-border/y - 2
show view/gui
]
view
]
; general case "set" operation
modify: func [model label value][
model/modify label value
model/propagate/only label
]
; just an example controler method
randomize: func [
model
label
][
modify model label random copy get in model/data label
]
]
ids: make controller! []
ids/new-model
do-events