柔性:是否存在无痛的编程数据绑定?
-
08-06-2019 - |
题
到目前为止,我只完成了一些 Flex 开发,但我更喜欢通过 mxml 文件以编程方式创建控件的方法,因为(并且 请, ,如果我错了,请纠正我!)我发现您不能同时拥有这两种方法——也就是说,在单独的 ActionScript 类文件中拥有类功能,但在 mxml 中声明所包含的元素。
在生产力方面似乎没有太大差异,但以编程方式进行数据绑定似乎有点不那么简单。我了解了 mxml 编译器如何转换数据绑定表达式。结果是一堆生成的回调和比 mxml 表示更多的行。所以这是问题: 有没有一种方法可以以编程方式进行数据绑定,而不会造成伤害?
解决方案
不要害怕 MXML。它非常适合布置视图。如果你自己写 可重复使用的 然后用 ActionScript 编写组件有时可能会给您更多的控制权,但对于不可重用的视图,MXML 更好。它更简洁,绑定非常容易设置,等等。
然而,纯 ActionScript 中的绑定并不需要那么麻烦。它永远不会像 MXML 那样简单,其中很多事情都为您完成,但不需要太多努力就可以完成。
你拥有的是 BindingUtils
它的方法 bindSetter
和 bindProperty
. 。我几乎总是使用前者,因为我通常想做一些工作,或者打电话 invalidateProperties
当值发生变化时,我几乎从来不想只是设置一个属性。
你需要知道的是,这两个返回一个类型的对象 ChangeWatcher
, ,如果由于某种原因想要删除绑定,则必须保留该对象。这就是 ActionScript 中的手动绑定比 MXML 中的手动绑定稍微不方便的原因。
让我们从一个简单的例子开始:
BindingUtils.bindSetter(nameChanged, selectedEmployee, "name");
这设置了一个将调用该方法的绑定 nameChanged
当。。。的时候 name
变量中对象的属性 selectedEmployee
变化。这 nameChanged
方法将收到的新值 name
属性作为参数,所以它应该看起来像这样:
private function nameChanged( newName : String ) : void
这个简单示例的问题在于,一旦设置了此绑定,每次指定对象的属性发生更改时都会触发该绑定。变量的值 selectedEmployee
可能会改变,但绑定仍然是为变量之前指向的对象设置的。
有两种方法可以解决这个问题:要么保持 ChangeWatcher
由返回 BindingUtils.bindSetter
周围并打电话 unwatch
当您想要删除绑定(然后设置新绑定)或绑定到您自己时,就可以使用它。我将首先向您展示第一个选项,然后解释我所说的“与自己绑定”是什么意思。
这 currentEmployee
可以制作成 getter/setter 对并像这样实现(仅显示 setter):
public function set currentEmployee( employee : Employee ) : void {
if ( _currentEmployee != employee ) {
if ( _currentEmployee != null ) {
currentEmployeeNameCW.unwatch();
}
_currentEmployee = employee;
if ( _currentEmployee != null ) {
currentEmployeeNameCW = BindingUtils.bindSetter(currentEmployeeNameChanged, _currentEmployee, "name");
}
}
}
发生的情况是,当 currentEmployee
属性设置后,它会查看是否有先前的值,如果有,则删除该对象的绑定(currentEmployeeNameCW.unwatch()
),然后它设置私有变量,除非新值是 null
为 name
财产。最重要的是它节省了 ChangeWatcher
由绑定调用返回。
这是一个基本的绑定模式,我认为它工作得很好。然而,有一个技巧可以让它变得更简单。您可以改为绑定自己。而不是每次都设置和删除绑定 currentEmployee
属性更改您可以让绑定系统为您完成。在你的 creationComplete
处理程序(或构造函数或至少提前一段时间)您可以像这样设置绑定:
BindingUtils.bindSetter(currentEmployeeNameChanged, this, ["currentEmployee", "name"]);
这不仅建立了绑定 currentEmployee
属性于 this
, ,而且还到 name
该对象上的属性。所以任何时候改变方法 currentEmployeeNameChanged
将被调用。没有必要保存 ChangeWatcher
因为永远不需要删除绑定。
第二个解决方案在很多情况下都有效,但我发现第一个解决方案有时是必要的,特别是在使用非视图类中的绑定时(因为 this
必须是事件调度程序并且 currentEmployee
必须可绑定才能工作)。
其他提示
从今天起它就存在了。:)
我刚刚将我的 ActionScript 数据绑定项目作为开源发布: http://code.google.com/p/bindage-tools
BindageTools 是 BindingUtils 的替代品(参见那里的文字游戏?),它使用流畅的 API,您可以在其中以管道样式声明数据绑定:
Bind.fromProperty(person, "firstName")
.toProperty(firstNameInput, "text");
双向绑定:
Bind.twoWay(
Bind.fromProperty(person, "firstName"),
Bind.fromProperty(firstNameInput, "text"));
显式数据转换和验证:
Bind.twoWay(
Bind.fromProperty(person, "age")
.convert(valueToString()),
Bind.fromProperty(ageInput, "text")
.validate(isNumeric()) // (Hamcrest-as3 matcher)
.convert(toNumber()));
ETC。该网站上还有更多示例。还有很多其他功能,快来看看。 - 马修
编辑:更新的API
将组件的 MXML 和 ActionScript 分离到单独的文件中的一种方法是执行类似于 ASP.Net 1.x 代码隐藏模型的操作。在此模型中,声明性部分(本例中为 MXML)是命令性部分(ActionScript)的子类。所以我可能会声明这样一个类的代码:
package CustomComponents
{
import mx.containers.*;
import mx.controls.*;
import flash.events.Event;
public class MyCanvasCode extends Canvas
{
public var myLabel : Label;
protected function onInitialize(event : Event):void
{
MyLabel.text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.";
}
}
}
...以及像这样的标记:
<?xml version="1.0" encoding="utf-8"?>
<MyCanvasCode xmlns="CustomComponents.*"
xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="onInitialize(event)">
<mx:Label id="myLabel"/>
</MyCanvasCode>
正如您从这个示例中看到的,这种方法的缺点是您必须声明如下控件 我的标签 在两个文件中。
我通常使用一种方法将 mxml 和动作脚本一起使用:我的所有 mxml 组件都继承自操作脚本类,我在其中添加了更复杂的代码。然后就可以在mxml文件中引用该类实现的事件监听器了。
问候,
露丝