groovy的可绑定/可否决属性的异常改变了侦听器

时间:2014-04-08 14:00:48

标签: groovy bindable

似乎有两种情况,通过@Bindable分配到绑定的groovy属性不会调用侦听器:

(1)如果属性是在类本身内分配的,例如this.prop = newval,或简称为prop = newval

(2)如果属性的值没有改变obj.prop = oldval

有解决方法吗?理想情况下,它将支持简单的(.)prop=语法。

代码示例:

import java.beans.*
import groovy.beans.*

int changes = 0
def obj = Binding.newInstance()
obj.propertyChange = { changes++ }
obj.prop = "1st change"   // change recorded
obj.twoChanges()          // no changes recorded
obj.prop = obj.prop       // no change recorded
assert changes == 4       // fails: changes is 1

class Binding {
  @Bindable String prop
  def twoChanges() {
    prop = "2nd change"
    this.prop = "3rd change"
  }
}

3 个答案:

答案 0 :(得分:2)

通过创建隐藏的@Bindable属性(mprop)并仅提供prop的getter和setter而没有名为prop的实际属性,我能够使用您的语法不变。除了将属性设置为相同值(检测到4个更改中的3个)之外,这适用于所有内容:

import java.beans.*
import groovy.beans.*

int changes = 0
def obj = Binding.newInstance()
obj.propertyChange = { changes++ }
obj.prop = "1st change"   // change recorded
obj.twoChanges()          // two changes recorded
obj.prop = obj.prop       // no change recorded
assert changes == 4       // fails: changes is 3


class Binding {
  @Bindable String mprop           // changed from prop to mprop
  def setProp(x) {setMprop(x)}     // new setter
  def getProp() {getMprop()}       // new getter
  def twoChanges() {
    prop = "2nd change"
    this.prop = "3rd change"
  }
}

答案 1 :(得分:1)

对于(1),@Bindable是一个AST,它生成自定义的setter,以及当你访问类中的属性时,它不会通过setter。这有效:

import java.beans.*
import groovy.beans.*

int changes = 0
def obj = Binding.newInstance()
obj.propertyChange = { changes++ }
obj.prop = "1st change"   // change recorded
obj.twoChanges()          // no changes recorded
obj.prop = obj.prop       // no change recorded
assert changes == 3       // fails: changes is 1

class Binding {
  @Bindable String prop
  def twoChanges() {
    setProp( "2nd change" )
    this.setProp( "3rd change"  )
  }
}

对于(2),好像,它似乎是PropertyChangeListener的{​​{3}},因为该属性未被更改。也许您可以提供standard behavior,或者只创建一个自定义设置器。

答案 2 :(得分:0)

这是我最终如何做到这一点,而不需要使用@Bindable。我愿意接受建议,尤其是this.with {}

class Obj {
  int val = 0
  static int numCalls = 0
  List assigns = []

  void setProperty(String name, Object value) {
    this.@"$name" = value
    assigns << [name: value]
    numCalls ++
  }

  int nop() {
    this.with { 
      val = val 
    }
  }

  int inc() {
    this.with { 
      this.val += 1  
    }
    return this.val
  }

}

def obj = Obj.newInstance()
assert obj.val == 0 && Obj.numCalls == 0
assert obj.inc() == 1 && obj.val == 1 && Obj.numCalls == 1
assert obj.nop() == 1 && obj.val == 1 && Obj.numCalls == 2 && obj.assigns.size() == 2