Domanda

Finora ho sviluppato solo un po' di Flex, ma ho preferito l'approccio di creare controlli a livello di codice sui file mxml, perché (e Per favore, correggimi se sbaglio!) Ho dedotto che non è possibile avere entrambe le cose, ovvero avere la funzionalità della classe in un file di classe ActionScript separato ma avere gli elementi contenuti dichiarati in mxml.

Non sembra esserci molta differenza in termini di produttività, ma eseguire l'associazione dei dati a livello di codice sembra un po' meno che banale.Ho dato un'occhiata a come il compilatore mxml trasforma le espressioni di associazione dati.Il risultato è un insieme di callback generati e molte più righe rispetto alla rappresentazione mxml.Quindi ecco la domanda: esiste un modo per eseguire l'associazione dei dati a livello di codice che non implichi un mondo di danni?

È stato utile?

Soluzione

Non abbiate paura di MXML. È ottimo per disporre le viste. Se scrivi i tuoi componenti riutilizzabili , scriverli in ActionScript a volte può darti un po 'più di controllo, ma per le viste non riutilizzabili MXML è molto meglio. È più conciso, i collegamenti sono estremamente facili da configurare, ecc.

Tuttavia, i binding in ActionScript puro non devono essere così fastidiosi. Non sarà mai così semplice come in MXML dove vengono fatte molte cose per te, ma può essere fatto senza troppi sforzi.

Quello che hai è BindingUtils ed è i metodi bindSetter e bindProperty . Uso quasi sempre il primo, poiché di solito voglio fare un po 'di lavoro, o chiamare invalidateProperties quando i valori cambiano, quasi mai voglio solo impostare una proprietà.

Quello che devi sapere è che questi due restituiscono un oggetto del tipo ChangeWatcher , se vuoi rimuovere l'associazione per qualche motivo, devi aggrapparti a questo oggetto. Questo è ciò che rende i collegamenti manuali in ActionScript un po 'meno convenienti di quelli in MXML.

Cominciamo con un semplice esempio:

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

Questo imposta un'associazione che chiamerà il metodo nameChanged quando la proprietà name sull'oggetto nella variabile selectedEmployee cambia. Il metodo nameChanged riceverà il nuovo valore della proprietà name come argomento, quindi dovrebbe apparire così:

private function nameChanged( newName : String ) : void 

Il problema con questo semplice esempio è che una volta impostato questo binding si attiverà ogni volta che cambia la proprietà dell'oggetto specificato. Il valore della variabile selectedEmployee può cambiare, ma l'associazione è ancora impostata per l'oggetto a cui la variabile puntava prima.

Esistono due modi per risolvere questo problema: mantenere ChangeWatcher restituito da BindingUtils.bindSetter e chiamarci unfatch quando vuoi rimuovere l'associazione (e quindi impostare una nuova associazione), oppure associarti a te stesso. Ti mostrerò prima la prima opzione, quindi spiegherò cosa intendo vincolando a te stesso.

Il currentEmployee potrebbe essere trasformato in una coppia getter / setter e implementato in questo modo (mostrando solo il 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");
        }
    }
}

Quello che succede è che quando la proprietà currentEmployee sembra vedere se c'era un valore precedente, e in tal caso rimuove l'associazione per quell'oggetto ( currentEmployeeNameCW.unwatch () ), quindi imposta la variabile privata e, a meno che il nuovo valore sia null , imposta una nuova associazione per la proprietà name . Soprattutto, salva il ChangeWatcher restituito dalla chiamata vincolante.

Questo è un modello di rilegatura di base e penso che funzioni bene. Vi è, tuttavia, un trucco che può essere utilizzato per renderlo un po 'più semplice. Puoi invece legarti a te stesso. Invece di impostare e rimuovere i binding ogni volta che la proprietà currentEmployee cambia, puoi fare in modo che il sistema di binding lo faccia per te. Nel tuo gestore creationComplete (o costruttore o almeno qualche tempo prima) puoi impostare un'associazione in questo modo:

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

Questo imposta un'associazione non solo alla proprietà currentEmployee su this , ma anche alla proprietà name su questo oggetto. Quindi, ogni volta che si modifica il metodo verrà chiamato currentEmployeeNameChanged . Non è necessario salvare ChangeWatcher perché non sarà mai necessario rimuovere l'associazione.

La seconda soluzione funziona in molti casi, ma ho scoperto che a volte la prima è necessaria, soprattutto quando si lavora con associazioni in classi non view (poiché this deve essere un dispatcher di eventi e il currentEmployee deve essere vincolante affinché funzioni).

Altri suggerimenti

Esiste da oggi. :)

Ho appena rilasciato il mio progetto di associazione dei dati ActionScript come open source: http://code.google. com / p / bindage-tools

BindageTools è un'alternativa a BindingUtils (vedi il gioco delle parole lì?) che utilizza un'API fluente in cui dichiari i tuoi binding di dati in uno stile di pipeline:

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

Collegamenti bidirezionali:

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

Conversione e convalida dei dati espliciti:

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

Ecc. Ci sono molti altri esempi sul sito. Ci sono anche molte altre funzionalità: dai un'occhiata. --Matthew

Modifica: API aggiornate

Un modo per separare MXML e ActionScript per un componente in file separati consiste nel fare qualcosa di simile al codice 1.x ASP.Net dietro il modello. In questo modello la parte dichiarativa (in questo caso MXML) è una sottoclasse della parte imperativa (ActionScript). Quindi potrei dichiarare il codice dietro per una classe come questa:

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

... e il markup in questo modo:

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

Come puoi vedere da questo esempio, uno svantaggio di questo approccio è che devi dichiarare controlli come myLabel in entrambi i file.

c'è un modo che di solito uso per usare mxml e script di azioni insieme: tutti i miei componenti mxml ereditano da una classe di script di azione in cui aggiungo il codice più complesso. Quindi puoi fare riferimento ai listener di eventi implementati in questa classe nel file mxml.

Saluti,

Ruth

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top