flex actionscript-3 data-binding mxml

Flex: ¿existe un enlace de datos programático indoloro?



actionscript-3 data-binding (4)

No tengas miedo de MXML. Es genial para diseñar vistas. Si escribe sus propios componentes reutilizables , escribirlos en ActionScript a veces puede darle un poco más de control, pero para las vistas no reutilizables, MXML es mucho mejor. Es más escueto, los enlaces son extremadamente fáciles de configurar, etc.

Sin embargo, los enlaces en ActionScript puro no tienen por qué ser tan dolorosos. Nunca será tan simple como en MXML donde se hacen muchas cosas por ti, pero se puede hacer sin demasiado esfuerzo.

Lo que tienes es BindingUtils y sus métodos bindSetter y bindProperty . Casi siempre uso el primero, ya que generalmente quiero hacer algún trabajo, o llamar a invalidateProperties cuando los valores cambian, casi nunca me gusta establecer una propiedad.

Lo que necesita saber es que estos dos devuelven un objeto del tipo ChangeWatcher . Si desea eliminar el enlace por alguna razón, debe aferrarse a este objeto. Esto es lo que hace que los enlaces manuales en ActionScript sean un poco menos convenientes que los de MXML.

Comencemos con un ejemplo simple:

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

Esto configura un enlace que llamará al método nameChanged cuando la propiedad name en el objeto en la variable selectedEmployee cambie. El método nameChanged recibirá el nuevo valor de la propiedad del name como argumento, por lo que debería verse así:

private function nameChanged( newName : String ) : void

El problema con este ejemplo simple es que una vez que haya configurado este enlace, se activará cada vez que cambie la propiedad del objeto especificado. El valor de la variable selectedEmployee puede cambiar, pero el enlace todavía está configurado para el objeto al que apuntaba la variable.

Hay dos formas de resolver esto: o bien mantener el ChangeWatcher devuelto por BindingUtils.bindSetter y llamar a unwatch sobre él cuando desee eliminar el enlace (y luego configurar un nuevo enlace en su lugar) o vincularse a usted mismo. Primero te mostraré la primera opción, y luego explicaré lo que quiero decir uniéndote a ti mismo.

El currentEmployee podría convertirse en un par getter / setter e implementado así (solo mostrando el 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"); } } }

Lo que ocurre es que cuando se establece la propiedad currentEmployee , se busca ver si hubo un valor anterior, y si es así se elimina el enlace para ese objeto ( currentEmployeeNameCW.unwatch() ), se establece la variable privada y, a menos que el nuevo valor was null establece un nuevo enlace para la propiedad del name . Lo más importante es que guarda el ChangeWatcher devuelto por la llamada vinculante.

Este es un patrón básico vinculante y creo que funciona bien. Sin embargo, hay un truco que se puede usar para hacerlo un poco más simple. Usted puede unirse a usted mismo en su lugar. En lugar de configurar y eliminar enlaces cada vez que currentEmployee propiedad currentEmployee , puede hacer que el sistema de enlace lo haga por usted. En el controlador de creationComplete (o constructor o al menos un poco antes) puede configurar un enlace como este:

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

Esto configura un enlace no solo para la propiedad del currentEmployee en this , sino también para la propiedad del name en este objeto. Por lo tanto, cada vez que se cambie el método se currentEmployeeNameChanged a currentEmployeeNameChanged . No es necesario guardar ChangeWatcher porque nunca será necesario eliminar el enlace.

La segunda solución funciona en muchos casos, pero he descubierto que la primera a veces es necesaria, especialmente cuando se trabaja con enlaces en clases que no son de vista (ya que this tiene que ser un despachador de eventos y el currentEmployee tiene que ser enlazable para trabajo).

Hasta ahora he hecho un poco de desarrollo de Flex, pero he preferido el enfoque de crear controles programáticamente sobre archivos mxml, porque (y por favor , corríjanme si estoy equivocado). He llegado a la conclusión de que se puede '' t tiene ambas formas, es decir, tiene la funcionalidad de clase en un archivo de clase de ActionScript independiente, pero tiene los elementos contenidos declarados en mxml.

No parece haber mucha diferencia en términos de productividad, pero hacer un enlace de datos programáticamente parece algo menos que trivial. Eché un vistazo a cómo el compilador mxml transforma las expresiones de enlace de datos. El resultado es un grupo de devoluciones de llamada generadas y muchas más líneas que en la representación de mxml. Así que aquí está la pregunta: ¿hay alguna manera de hacer enlaces de datos programáticamente que no implique un mundo de dolor?


Una manera de separar MXML y ActionScript para un componente en archivos separados es haciendo algo similar al código ASP.Net 1.x detrás del modelo. En este modelo, la parte declarativa (el MXML en este caso) es una subclase de la parte imperativa (el ActionScript). Entonces podría declarar el código detrás de una clase como esta:

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."; } } }

... y el marcado de esta manera:

<?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>

Como se puede ver en este ejemplo, una desventaja de este enfoque es que debe declarar controles como myLabel en ambos archivos.


Hay una manera en que suelo usar mxml y Action Script juntos: todos mis componentes mxml heredan de una clase de script de acción donde agrego el código más complejo. Luego puede referirse a los detectores de eventos implementados en esta clase en el archivo mxml.

Saludos,

Piedad


Existe a partir de hoy. :)

Acabo de lanzar mi proyecto de enlace de datos de ActionScript como código abierto: http://code.google.com/p/bindage-tools

BindageTools es una alternativa a BindingUtils (¿ves juego de palabras allí?) Que usa una API fluida donde declaras tus enlaces de datos en un estilo de canalización:

Bind.fromProperty(person, "firstName") .toProperty(firstNameInput, "text");

Enlaces bidireccionales:

Bind.twoWay( Bind.fromProperty(person, "firstName"), Bind.fromProperty(firstNameInput, "text"));

Conversión y validación de datos explícitos:

Bind.twoWay( Bind.fromProperty(person, "age") .convert(valueToString()), Bind.fromProperty(ageInput, "text") .validate(isNumeric()) // (Hamcrest-as3 matcher) .convert(toNumber()));

Etc. Hay muchos más ejemplos en el sitio. También hay muchas otras características, ven a echar un vistazo. --Mateo

Editar: API actualizadas