Flex:nie pynloos programmatiese data binding bestaan?
-
08-06-2019 - |
Vra
Ek het net gedoen om'n bietjie van die Bult-ontwikkeling so ver, maar ek het verkies die benadering van die skep van beheer programmaties oor mxml lêers, omdat (en asseblief, korrigeer my as ek verkeerd is!) Ek versamel het dat jy nie kan dit beide maniere-dit is om te sê, het die klas funksies in'n aparte Action klas lêer, maar het die elemente vervat verklaar in mxml.
Daar lyk nie te veel van'n verskil produktiwiteit-wyse, maar om data bindend programmaties lyk ietwat minder as triviale.Ek het'n blik op hoe die mxml samesteller verander die data bindend uitdrukkings.Die resultaat is'n klomp van die gegenereerde verificaties en'n baie meer lyne as in die mxml verteenwoordiging.So hier is die vraag: is daar'n manier om dit te doen data bindend programmaties wat behels nie'n wêreld van seer?
Oplossing
Moenie bang wees vir MXML wees. Dit is wonderlik vir die uitleg van standpunte. As jy jou eie skryf herbruikbare komponente dan skryf hulle in Action soms gee jy 'n bietjie meer beheer, maar vir nie-herbruikbare uitsig MXML is baie beter. Dit is meer kortaf, bindings is extemely maklik op te rig, ens.
Maar bindings in suiwer Action hoef nie veel van 'n pyn wees. Dit sal nooit so eenvoudig soos in MXML waar 'n klomp dinge vir jou gedoen word, maar dit kan gedoen word met nie te veel moeite.
Wat jy is BindingUtils
en dis metodes bindSetter
en bindProperty
. Ek het amper altyd gebruik die voormalige, want ek gewoonlik wil om werk te doen, of bel invalidateProperties
wanneer waardes verander, het ek amper nooit wil net 'n eiendom te stel.
Wat jy moet weet, is dat hierdie twee terugkeer 'n voorwerp van die tipe ChangeWatcher
, as jy wil hê dat die bindende vir een of ander rede verwyder, moet jy om vas te hou aan hierdie voorwerp. Dit is wat maak handleiding bindings in Action 'n bietjie minder gerieflik as dié in MXML.
Kom ons begin met 'n eenvoudige voorbeeld:
BindingUtils.bindSetter(nameChanged, selectedEmployee, "name");
Dit stel 'n bindende dat die metode nameChanged
sal bel wanneer die eiendom name
op die voorwerp in die veranderlike selectedEmployee
veranderinge. Die nameChanged
metode sal die nuwe waarde van die eiendom name
as 'n argument te ontvang, sodat dit moet lyk soos volg:
private function nameChanged( newName : String ) : void
Die probleem met hierdie eenvoudige voorbeeld is dat wanneer jy die opstel van hierdie bindwerk dit sal elke keer afgegaan die eiendom van die gespesifiseerde voorwerp verander. Die waarde van die veranderlike selectedEmployee
kan verander, maar die bindende is nog vir die opstel van die voorwerp wat die veranderlike wys na voor.
Daar is twee maniere om hierdie op te los: óf om die ChangeWatcher
teruggekeer deur BindingUtils.bindSetter
om te hou en te bel unwatch
op dit wanneer jy wil die binding (en dan die opstel van 'n nuwe binding plaas) te verwyder, of bind aan jouself. Ek sal jou wys die eerste opsie eerste, en dan verduidelik wat ek bedoel deur binding aan jouself.
Die currentEmployee
kan gemaak word in 'n lucky / setter paar en geïmplementeer soos hierdie (net wat die 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");
}
}
}
Wat gebeur is dat wanneer die eiendom currentEmployee
is ingestel dit lyk om te sien of daar 'n vorige waarde, en as die bindende vir daardie voorwerp (currentEmployeeNameCW.unwatch()
) so verwyder, dan sit dit die private veranderlike, en tensy dit uit die nuwe waarde was null
stel 'n nuwe binding vir die eiendom name
. Die belangrikste is dit spaar die ChangeWatcher
teruggekeer deur die bindende oproep.
Dit is 'n basiese binding patroon en ek dink dit werk goed. Daar is egter 'n truuk wat gebruik kan word om dit 'n bietjie makliker te maak. Jy kan bind om jouself plaas. In plaas van die opstel en die verwydering van bindings elke keer as die eiendom currentEmployee
verander kan jy die bindende stelsel het dit vir jou doen. In jou creationComplete
hanteerder (of constructor of ten minste 'n paar keer vroeg) kan jy die opstel van 'n bindende soos so:
BindingUtils.bindSetter(currentEmployeeNameChanged, this, ["currentEmployee", "name"]);
Dit stel 'n bindende nie net om die eiendom currentEmployee
op this
, maar ook om die eiendom name
op hierdie voorwerp. So enige tyd óf verander die metode currentEmployeeNameChanged
sal genoem word. Daar is geen behoefte om die ChangeWatcher
red omdat die binding sal nooit weer hoef te verwyder.
Die tweede oplossing werk in baie gevalle, maar ek het gevind dat die eerste een is soms nodig, veral wanneer daar met bindings in 'n nie-oog klasse (sedert this
het om 'n gebeurtenis planner wees en die currentEmployee
het bindable te wees vir dit om te werk).
Ander wenke
Dit bestaan as van vandag.:)
Ek het sopas my Action data bindend projek as open source: http://code.google.com/p/bindage-tools
BindageTools is'n alternatief vir BindingUtils (sien die speel op woorde daar?) wat gebruik maak van'n vlot API waar jy verklaar jou data bindings in'n pyplyn styl:
Bind.fromProperty(person, "firstName")
.toProperty(firstNameInput, "text");
Twee-manier bindings:
Bind.twoWay(
Bind.fromProperty(person, "firstName"),
Bind.fromProperty(firstNameInput, "text"));
Eksplisiete data-omskakeling en validering:
Bind.twoWay(
Bind.fromProperty(person, "age")
.convert(valueToString()),
Bind.fromProperty(ageInput, "text")
.validate(isNumeric()) // (Hamcrest-as3 matcher)
.convert(toNumber()));
Ens.Daar is baie meer voorbeelde op die webwerf.Daar is baie van die ander funksies te kom kyk.--Mattheus
Edit:opgedateer APIs
Een manier om die MXML en Action skei vir 'n komponent in afsonderlike lêers is deur iets soortgelyk aan die ASP.Net 1.x kode agter model doen. In hierdie model die verklarende deel (die MXML in hierdie geval) is 'n subklas van die noodsaaklikheid deel (die Action). So kan ek agter verklaar die kode vir 'n klas soos volg:
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.";
}
}
}
... en die opmaak soos volg:
<?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>
Soos jy kan sien uit hierdie voorbeeld, 'n disadvatage van hierdie benadering is dat jy hoef te beheer soos verklaar mylabel in beide lêers.
Daar is 'n manier dat ek gewoonlik gebruik om mxml en aksie script saam gebruik: Al my mxml komponente besit van 'n aksie script klas waar ek voeg die meer komplekse kode. Dan kan jy verwys na gebeurtenis luisteraars in hierdie klas geïmplementeer in die mxml lêer.
Groete,
Ruth