ZK 6中的MVVM初探

MVVM与MVC

在上一篇文章中,我们已经看到Ajax框架ZK如何采用CSS选择器启发的Controller来在View中连接UI组件并监听它们的事件。 在此ZK MVC模式下, View中的UI组件无需绑定到任何Controller方法或数据对象。 使用选择器模式作为将View状态和事件映射到Controller的灵活性,使代码更适应更改。

MVVM在相反方向上实现关注点分离。 在这种模式下,视图模型和绑定器机制代替了控制器。 绑定器将View的请求映射到View-Model中的动作逻辑,并更新双方的任何值(数据),从而允许View-Model独立于任何特定的View。

ZK 6中的MVVM的剖析

以下是ZK 6的MVVM模式的示意图:

以下是图中未传达的一些其他要点:
BindComposer:

  • 实现ZK的标准控制器接口(Composer&ComposerExt)
  • 默认实现就足够了,不需要修改

视图:

  • 通知活页夹调用哪种方法以及在视图模型上更新哪些属性

视图模型:

  • 只是一个POJO
  • 通过Java注释与活页夹进行通信

MVVM运行中

考虑在不知道确切的UI标记的情况下显示简化清单的任务。 库存是项目的集合,因此我们具有以下对象的表示形式:

public class Item {
 private String ID;
 private String name;
 private int quantity;
 private BigDecimal unitPrice;

        //getters & setters
}

期望可以选择并操作列表中的项目也很有意义。 因此,根据到目前为止的知识和假设,我们可以继续执行视图模型。

public class InventoryVM {
 
    ListModelList<Item> inventory;
    Item selectedItem;
  
    public ListModelList<Item> getInventory(){
        inventory = new ListModelList<Item>(InventoryDAO.getInventory());
        return inventory;
    }

    public Item getSelectedItem() {
        return selectedItem;
    }
 
    public void setSelectedItem(Item selectedItem) {
        this.selectedItem = selectedItem;
    }

}

在这里,我们为View-Model实现提供了一个典型的POJO,以及带有其getter和setter的数据。

查看实施,“采取行动”

现在,假设我们后来了解到View的要求只是一个简单的表格显示:

实现上述UI的可能标记是:

<window title='Inventory' border='normal' apply='org.zkoss.bind.BindComposer' 
 viewModel='@id('vm') @init('lab.zkoss.mvvm.ctrl.InventoryVM')' >
 <listbox model='@load(vm.inventory)' width='600px' >
  <auxhead><auxheader label='Inventory Summary' colspan='5' align='center'/> </auxhead>
  <listhead>
   <listheader width='15%' label='Item ID' sort='auto(ID)'/>
   <listheader width='20%' label='Name' sort='auto(name)'/>
   <listheader width='20%' label='Quantity' sort='auto(quantity)'/>
   <listheader width='20%' label='Unit Price' sort='auto(unitPrice)'/>
   <listheader width='25%' label='Net Value'/>
  </listhead>
  <template name='model' var='item'>
   <listitem>
    <listcell><label value='@load(item.ID)'/></listcell>
    <listcell><label value='@load(item.name)'/></listcell>
    <listcell><label value='@load(item.quantity)'/></listcell>
    <listcell><label value='@load(item.unitPrice)'/></listcell>
    <listcell><label value='@load(item.unitPrice * item.quantity)'/></listcell>
   </listitem> 
  </template>
 </listbox>
</window>

让我们在这里详细说明一下标记。

  • 在第1行,我们将默认的BindComposer应用于Window组件,该组件使Window的所有子组件均受BindComposer的影响。
  • 在下一行,我们指示BindComposer实例化哪个View-Model类,并为View-Model实例提供ID,以便我们对其进行引用。
  • 由于我们正在将数据集合加载到列表框,因此在第3行,我们将View-Model实例的属性“库存”(即Item对象的集合)分配给列表框的属性“模型”。
  • 然后,在第12行,我们在模板组件上使用该模型。 模板根据收到的模型迭代其封闭的组件。 在这种情况下,我们有5个列表项,它们在列表框中组成一行。
  • 在每个Listcell中,我们加载每个对象的属性并将其显示在Labels中。

通过ZK的绑定系统,我们能够访问View-Model实例中的数据,并使用批注将其加载到View中。

查看实施,“采取两个”

假设在以后的开发中,我们同意当前的表格显示在我们的演示文稿中占用了太多空间,并且现在要求我们仅在组合框中选择该项目时才显示该项目的详细信息,如下所示:

尽管表示和行为(仅在用户选择时才显示详细信息)与我们以前的实现有所不同,但是View-Model类不需要大量修改。 由于仅当在组合框中选中某个项目的细节时才会显示它的细节,所以很明显,我们需要处理'onSelect'事件,让我们添加一个新方法doSelect

public class InventoryVM {
 
    ListModelList<Item> inventory;
    Item selectedItem;

    @NotifyChange('selectedItem')
    @Command
    public void doSelect(){ }
    
    //getters & setters

}

在我们的例子中,用@Command注释的方法使其有资格通过其名称从我们的标记中调用:

<combobox onSelect='@command('doSelect')' >

注释@NotifyChange('selectedItem')允许用户在组合框中选择新项目时自动更新selectedItem属性。 出于我们的目的,方法doSelect不需要其他实现。 完成这些更改后,我们现在可以看到经过稍微修改的View-Model如何与我们的新标记一起工作:

<window title='Inventory' border='normal' apply='org.zkoss.bind.BindComposer' 
 viewModel='@id('vm') @init('lab.zkoss.mvvm.ctrl.InventoryVM')' width='600px'>
 ...
  <combobox model='@load(vm.inventory)' 
     selectedItem='@bind(vm.selectedItem)' 
      onSelect='@command('doSelect')' >
   <template name='model' var='item'>
    <comboitem label='@load(item.ID)'/>
   </template>
   <comboitem label='Test'/>
  </combobox>
  <listbox  visible='@load(not empty vm.selectedItem)' width='240px'>
   <listhead>
    <listheader ></listheader>
    <listheader ></listheader>
   </listhead>
   <listitem>
    <listcell>
     <label value='Item Name: ' />
    </listcell>
    <listcell>
     <label value='@load(vm.selectedItem.name)' />
    </listcell>
   </listitem>
   <listitem>
    <listcell>
     <label value='Unit Price: ' />
    </listcell>
    <listcell>
     <label value='@load(vm.selectedItem.unitPrice)' />
    </listcell>
   </listitem>
   <listitem>
    <listcell>
     <label value='Units in Stock: ' />
    </listcell>
    <listcell>
     <label value='@load(vm.selectedItem.quantity)' />
    </listcell>
   </listitem>
   <listitem>
    <listcell>
     <label value='Net Value: ' />
    </listcell>
    <listcell>
     <label value='@load(vm.selectedItem.unitPrice * vm.selectedItem.quantity)' />
    </listcell>
   </listitem>
  </listbox>
 ...
</window>
  • 在第4行,我们将数据收集清单加载到Combobox的model属性,以便它可以使用在第7行声明的Template组件迭代显示数据模型中每个Item对象的ID。
  • 在第5行,selectedItem属性指向该Item对象列表上最近选择的Item。
  • 在第6行,我们已将onSelect事件映射到View-Model的doSelect方法
  • 在第12行,仅当View-Model中的selectedItem属性不为空时,才使包含项明细的列表框可见(在组合框中选择一个项之前,selectedItem将保持为空)。
  • 然后加载selectedItem的属性以填充列表框。

概括

在MVVM模式下,我们的View-Model类将其数据和方法公开给活页夹; 没有参考任何特定的View组件。 View实现通过绑定器访问数据或调用事件处理程序。

在本文中,我们仅介绍ZK的MVVM机制的基本原理。 活页夹显然不仅限于从视图模型中加载数据。 除了将数据从View保存到ViewModel之外,我们还可以混合使用View to View-Model通信来注入数据转换器和验证器。 MVVM模式也可以与MVC模型结合使用。 也就是说,如果我们愿意的话,我们也可以通过MVC Selector机制连接组件并监听触发事件。

我们稍后将深入探讨其中一些主题。

参考:我们的JCG合作伙伴 Lance Lu在Tech Dojo博客上对ZK 6中的MVVM进行初步了解


翻译自: https://www.javacodegeeks.com/2012/06/first-look-at-mvvm-in-zk-6.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值