Model view controller Rebol VID MVC:如果Rebol不';不支持自定义事件?

Model view controller Rebol VID MVC:如果Rebol不';不支持自定义事件?,model-view-controller,rebol,Model View Controller,Rebol,假设我有一个模型/控制器,有两个同时的视频格式。如果Rebol不支持自定义事件,我将如何更新指向同一模型的两个视图?我继续进行,并从实现属性编辑器MVC中获得了乐趣 此示例允许您直接从GUI动态创建模型和视图,因此它非常适合显示实际运行的系统 当多个视图编辑同一数据时,您将看到它们保持同步。多个模型可能每个都有多个视图 这只是一个例子,展示了在REBOL中构建MVC模式是多么容易。事实上,REBOL中的许多构造在精神上已经是MVC了,即使它们没有明确地作为MVC进行营销 rebol [

假设我有一个模型/控制器,有两个同时的视频格式。如果Rebol不支持自定义事件,我将如何更新指向同一模型的两个视图?

我继续进行,并从实现属性编辑器MVC中获得了乐趣

此示例允许您直接从GUI动态创建模型和视图,因此它非常适合显示实际运行的系统

当多个视图编辑同一数据时,您将看到它们保持同步。多个模型可能每个都有多个视图

这只是一个例子,展示了在REBOL中构建MVC模式是多么容易。事实上,REBOL中的许多构造在精神上已经是MVC了,即使它们没有明确地作为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


我继续进行,并从实现属性编辑器MVC中获得了乐趣

此示例允许您直接从GUI动态创建模型和视图,因此它非常适合显示实际运行的系统

当多个视图编辑同一数据时,您将看到它们保持同步。多个模型可能每个都有多个视图

这只是一个例子,展示了在REBOL中构建MVC模式是多么容易。事实上,REBOL中的许多构造在精神上已经是MVC了,即使它们没有明确地作为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


如果您在这里提供一个代码示例,它将非常有用。基本上说“这是我知道的有用的东西,好吧,很好”,然后“但这是一个阻碍我实现我想要的东西…”我还没有在尝试之前等待建议,但ok会尝试以下方法:)实现MVC的方法太多了,除非你告诉我们你是如何实现的,否则答案是不可能的。不是太多:你有一个模型,你想在模型字段每次更改时自动更新2个视图,您如何在rebol中传播/广播该更改?当然,模型必须是与视图不同的对象:目的是分离实体,rebol倾向于创建单个文件并混合所有内容。我使用liquid Dataflow模块在原子级别上实现MVC类型的约束。但这意味着您的数据和GUI必须液化,玻璃就是这样。使用liquid还意味着您可以改变编程模式(从命令式到数据流),因此这可能是一个相当大的方法变化。基本上说“这是我知道的有用的东西,好吧,很好”,然后“但这是一个阻碍我实现我想要的东西…”我还没有在尝试之前等待建议,但ok会尝试以下方法:)实现MVC的方法太多了,除非你告诉我们你是如何实现的,否则答案是不可能的。不是太多:你有一个模型,你想在模型字段每次更改时自动更新2个视图,您如何在rebol中传播/广播该更改?当然,模型必须是与视图不同的对象:目的是分离实体,rebol倾向于创建单个文件并混合所有内容。我使用liquid Dataflow模块在原子级别上实现MVC类型的约束。但这意味着您的数据和GUI必须液化,玻璃就是这样。使用liquid还意味着改变编程模式(从命令式到数据流),因此这可能是一个相当大的方法变化。