ZK Model-View-ViewModel (MVVM)

来源:互联网 发布:100本网络禁书txt下载 编辑:程序博客网 时间:2024/04/30 03:38

ZK supports the Model-View-ViewModel (MVVM) design pattern which automates the data-binding tasks that developers would have to otherwise implement in a traditional controller. This pattern divides an application into three parts.

.The Model consists of application data and business rules.
.The View means user interface. The zul page which contains ZK components represents this part. An user's interaction with components triggers events to be sent to controllers.
.The ViewModel is type of View abstraction which contains a View's state and behavior. It is responsible for exposing data from the Model to the View and providing required action requested from the View
.There is a binder in ZK which synchronizes data between ViewModel and View and handle events automatically according to your data binding expressions. You don't need to control components by yourself.


1.A user clicks "Search" button and a corresponding event is sent.
2.ZK's binder invokes the corresponding command method in the ViewModel.
3.The method accesses data from Model and updates some ViewModel's properties.
4.ZK's binder reloads changed properties from the ViewModel to update component's states.


Write a ViewModel:
ViewModel is an abstraction of View. Therefore when we design a ViewModel, we should analyse UI's functions for what states it contains and what behaviours it has. In the ViewModel of this demo, which contains the state : keyword, car list, selected car and behavior search

public class SearchViewModel{         private String keyword;    private List<Car> carList;    private Car selectedCar;     public void search(){        ...    }    //getter & setter ...}
Annotate the command method :
Any behaviour which can be requested by a View is a command in a ViewModel, you should apply an annotation@Command on the behaviour method (also called command method). After the execution of the command method, a ViewModel annotated with@NotifyChange would reflect the state changes made in View.
public class SearchViewModel{    ...     @Command    @NotifyChange("carList")    public void search(){        carList = carService.search(keyword);    }}
Bind View to ViewModel :
To bind View to a ViewModel, you should apply a composer called org.zkoss.bind.BindComposer, and use @id('VMID')@init('FULL.QUALIFIED.CLASSNAME') syntax in viewModel attribute. @id() is used to set ViewModel's id to an arbitrary variable name of your choice. You will use this id to reference ViewModel's properties.@init() is used to initialize the ViewModel object.
<window apply="org.zkoss.bind.BindComposer"    viewModel="@id('vm') @init('demo.getting_started.mvvm.SearchViewModel')">    ...</window>
Bind attribute with property :
To bind a component attribute to a property of ViewModel, you use @bind(VMID.PROPERTY_NAME) on the attribute of component.
<textbox value="@bind(vm.keyword)" />
Bind event with command :
To bind a component event to a command of ViewModel, you use @command('COMMAND_NAME') on the event of component.
<button label="Search" onClick="@command('search')" />


View
<window title="Search" width="600px" border="normal" apply="org.zkoss.bind.BindComposer"    viewModel="@id('vm') @init('demo.getting_started.mvvm.SearchViewModel')">    <hbox align="center">        Keyword:        <textbox value="@bind(vm.keyword)" />        <button label="Search" image="/widgets/getting_started/img/search.png" onClick="@command('search')" />    </hbox>    <listbox height="160px" model="@bind(vm.carList)" emptyMessage="No car found in the result"    selectedItem="@bind(vm.selectedCar)" style="margin-top:10px">        <listhead>            <listheader label="Model" />            <listheader label="Make" />            <listheader label="Price" width="20%"/>        </listhead>        <template name="model">            <listitem>                <listcell label="@bind(each.model)"></listcell>                <listcell label="@bind(each.make)"></listcell>                <listcell>$<label value="@bind(each.price)" /></listcell>            </listitem>        </template>    </listbox>    <hbox style="margin-top:20px" visible="@bind(not empty vm.selectedCar)">        <image src="@bind(vm.selectedCar.preview)" style="padding:10px" />        <vbox>            <hlayout>                Model : <label value="@bind(vm.selectedCar.model)" style="font-weight:bold"/>            </hlayout>            <hlayout>                Make : <label value="@bind(vm.selectedCar.make)" style="font-weight:bold"/>            </hlayout>            <hlayout>                Price :                 <span>$<label value="@bind(vm.selectedCar.price)" style="font-weight:bold"/></span>            </hlayout>            <label value="@bind(vm.selectedCar.description)" />        </vbox>    </hbox></window>
ViewModel
package demo.getting_started.mvvm; import java.util.List; import org.zkoss.bind.annotation.Command;import org.zkoss.bind.annotation.NotifyChange; import demo.getting_started.tutorial.Car;import demo.getting_started.tutorial.CarService;import demo.getting_started.tutorial.CarServiceImpl; public class SearchViewModel {         private String keyword;    private List<Car> carList;    private Car selectedCar;         private CarService carService = new CarServiceImpl();         public void setKeyword(String keyword) {        this.keyword = keyword;    }    public String getKeyword() {        return keyword;    }     public List<Car> getCarList(){        return carList;    }                  public void setSelectedCar(Car selectedCar) {        this.selectedCar = selectedCar;    }    public Car getSelectedCar() {        return selectedCar;    }          @Command    @NotifyChange("carList")    public void search(){        carList = carService.search(keyword);    }}
Model

package demo.getting_started.tutorial; public class Car {     private Integer id;    private String model;    private String make;    private String preview;    private String description;    private Integer price;     public Car() {    }     public Car(Integer id, String model, String make, String description, String preview, Integer price) {        this.id = id;        this.model = model;        this.make = make;        this.preview = preview;        this.description = description;        this.price = price;    }     public Integer getId() {        return id;    }     public void setId(Integer id) {        this.id = id;    }     public String getMake() {        return make;    }     public void setMake(String make) {        this.make = make;    }     public String getPreview() {        return preview;    }     public void setPreview(String preview) {        this.preview = preview;    }     public String getDescription() {        return description;    }     public void setDescription(String description) {        this.description = description;    }     public Integer getPrice() {        return price;    }     public void setPrice(Integer price) {        this.price = price;    }     public String getModel() {        return model;    }     public void setModel(String model) {        this.model = model;    }}
package demo.getting_started.tutorial; import java.util.List; public interface CarService {     /**     * Retrieve all cars in the catalog.     * @return all cars     */    public List<Car> findAll();         /**     * search cars according to keyword in name and company.     * @param keyword for search     * @return list of car that match the keyword     */    public List<Car> search(String keyword);}



0 0