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

时间:2020-03-05 18:40:15  来源:igfitidea点击:

到目前为止,我只做过一些Flex开发,但是我更喜欢以编程方式在mxml文件上创建控件的方法,因为(并且,如果我错了,请纠正我!)不能同时使用这两种方法-也就是说,具有单独的ActionScript类文件中的类功能,但具有在mxml中声明的包含的元素。

生产率方面似乎并没有多大区别,但是以编程方式进行数据绑定似乎并不容易。我看了一下mxml编译器如何转换数据绑定表达式。结果是一堆生成的回调和比mxml表示形式多得多的行。因此,问题就来了:有没有一种方法可以通过编程方式进行数据绑定,而不会造成伤害呢?

解决方案

回答

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

但是,纯ActionScript中的绑定不必那么费劲。它永远不会像在MXML中那样为我们完成很多事情那样简单,但是可以花很多精力来完成它。

你拥有的是BindingUtils,它是方法bindSetter和bindProperty。我几乎总是使用前者,因为我通常想做一些工作,或者在值更改时调用" invalidateProperties",所以我几乎从不希望设置属性。

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

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

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

这样设置了一个绑定,当变量" selectedEmployee"中对象的" name"属性发生更改时,该绑定将调用方法" nameChanged"。 nameChanged方法将使用name属性的新值作为参数,因此应如下所示:

private function nameChanged( newName : String ) : void

这个简单示例的问题在于,一旦设置了此绑定,它将在每次指定对象的属性更改时触发。变量" selectedEmployee"的值可能会更改,但是仍然为该变量之前指向的对象设置了绑定。

有两种解决方法:或者保留由BindingUtils.bindSetter返回的ChangeChangeer,然后在要删除绑定(然后设置新的绑定)时对其调用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属性时,它会查看是否存在一个先前的值,如果存在,则会删除该对象的绑定(currentcurrentNameCW.unwatch()),然后设置私有变量,除非新值是null,否则将为name属性设置新的绑定。最重要的是,它保存了绑定调用返回的ChangeWatcher

这是一种基本的绑定模式,我认为它可以正常工作。但是,有一个技巧可以使它更简单。我们可以改为绑定自己。我们不必让currentEmployee属性每次更改都设置和删除绑定,而是可以让绑定系统为我们完成。在creationComplete处理程序(或者构造函数或者至少提前一段时间)中,我们可以像这样设置绑定:

BindingUtils.bindSetter(currentEmployeeNameChanged, this, ["currentEmployee", "name"]);

这样不仅可以绑定到this上的currentEmployee属性,还可以绑定到该对象上的name属性。因此,无论何时更改方法,都会调用currentEmployeeNameChanged方法。无需保存ChangeWatcher,因为永远不需要删除绑定。

第二种解决方案在很多情况下都可以使用,但是我发现第一个解决方案有时是必要的,尤其是在非视图类中使用绑定时(因为" this"必须是事件调度程序,而" currentEmployee"必须是具有约束力才能正常工作)。

回答

将组件的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之类的控件。

回答

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

问候,

露丝