Flex:是否存在无痛的程序化数据绑定?

时间:2008-08-18 06:15:09

标签: flex actionscript-3 data-binding mxml

到目前为止我只完成了一些Flex开发,但我更喜欢以编程方式在mxml文件上创建控件的方法,因为(并且,如果我错了,请更正我!)我已经收集到你不能两种方式 - 也就是说,将类功能放在一个单独的ActionScript类文件中,但是包含的元素是用mxml声明的。

似乎没有太大的生产力差异,但以编程方式进行数据绑定似乎有点不重要。我看了一下mxml编译器如何转换数据绑定表达式。结果是一堆生成的回调和比mxml表示中更多的行。所以这里有一个问题:有没有办法以编程方式进行数据绑定而不涉及受伤的世界?

4 个答案:

答案 0 :(得分:29)

不要害怕MXML。它非常适合布置视图。如果您编写自己的可重用组件,那么在ActionScript中编写它们有时可能会给您更多控制权,但对于不可重用的视图,MXML要好得多。它更简洁,绑定很容易设置等等。

但是,纯ActionScript中的绑定不需要那么多痛苦。它永远不会像MXML那样简单,为你做了很多事情,但是可以不花太多精力完成。

您所拥有的是BindingUtils及其方法bindSetterbindProperty。我几乎总是使用前者,因为我通常想做一些工作,或者当值改变时调用invalidateProperties,我几乎从不想要设置属性。

您需要知道的是,这两个返回ChangeWatcher类型的对象,如果由于某种原因想要删除绑定,则必须保留此对象。这使得ActionScript中的手动绑定比MXML中的手动绑定更不方便。

让我们从一个简单的例子开始:

BindingUtils.bindSetter(nameChanged, selectedEmployee, "name");

这将设置一个绑定,当变量nameChanged中对象的name属性发生更改时,该绑定将调用方法selectedEmployeenameChanged方法将接收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必须是事件调度程序而且{ {1}}必须是可绑定的才能工作)。

答案 1 :(得分:8)

它存在于今天。 :)

我刚刚发布了我的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()));

等。网站上有更多的例子。还有许多其他功能 - 来看看。 --Matthew

编辑:更新的API

答案 2 :(得分:2)

将组件的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>

从这个例子中可以看出,这种方法的缺点是你必须在两个文件中声明像 myLabel 这样的控件。

答案 3 :(得分:0)

我通常使用一种方法将mxml和动作脚本一起使用:我的所有mxml组件都继承自动作脚本类,我在其中添加了更复杂的代码。然后,您可以在mxml文件中引用此类中实现的事件侦听器。

此致

露丝