Zurück   Flashforum > Flex und AIR > Flex programmieren

Antwort
 
LinkBack Themen-Optionen Ansicht
Alt 09-12-2007, 17:04   #1 (permalink)
Neuer User
 
Benutzerbild von Utopian
 
Registriert seit: May 2003
Beiträge: 1.031
Verständnisfrage: Eigene MXML Komponente mit AS3 ansprechen

Hi,

tolles Forum, ich hoffe hier kann mir jemand weiterhelfen.

Ich habe eine Main Applikation, die in verschiedenen States verschiedene eigene Komponenten verwenden soll. D.h. eine Eingabemaske für Kundendaten steckt z.B. in einem eigenen State.

Nun möchte ich aber nicht, dass ich in das MXML Dokument der Komponente die gesamte Logik schreibe, sondern für jede Komponente eine eigene AS Datei habe.

Meine Hauptapplikation (Nur ein Menü, welches je nach Klick verschiedene States aufruft. Im State AddCustomers, steckt die Komponente "AddCustomers".)

PHP-Code:
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" applicationComplete="init()" layout="absolute" xmlns:ns1="lib.components.*" width="800" height="600">

    <mx:Script>
        <![CDATA[
            import mx.events.MenuEvent;
            import mx.controls.Alert;
            
            public function init():void {
                menubar.addEventListener(MenuEvent.ITEM_CLICK, menueChanged);
            }
            
            public function menueChanged(event:MenuEvent):void {
                
                switch(event.label.toString()) {
                    case "Patient hinzufügen": AddCustomers(event); 
                    break;
                }            
            }
        
            public function AddCustomers(event:MenuEvent):void {
                this.setCurrentState("AddCustomers");        
            }
    
        ]]>
    </mx:Script>

    <mx:MenuBar x="0" y="0" id="menubar" labelField="@label" width="100%">
        <mx:XMLList>
            <menuitem label="Verwaltung">
                <menuitem label="Patienten">
                    <menuitem label="Patient hinzufügen"/>
                </menuitem>
                <menuitem type="separator"/> 
                <menuitem label="Firmen" enabled="false"/>
                <menuitem label="Leistungen" enabled="false"/>
            </menuitem>
        </mx:XMLList>
    </mx:MenuBar>    
    
    <mx:states>
        <mx:State name="AddCustomers">
            <mx:AddChild>
                <ns1:AddCustomers x="10" y="30">
                </ns1:AddCustomers>
            </mx:AddChild>
        </mx:State>
    </mx:states>
    
</mx:WindowedApplication>
Die Komponente (diese besteht aus einem Formular und implementiert die AS Datei für die Komponente):

PHP-Code:
<?xml version="1.0" encoding="utf-8"?>

<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="360" height="445">

    <mx:Script>
        <![CDATA[
            import lib.components.AddCustomersAS;
            public var _AddCustomersAS:AddCustomersAS = new AddCustomersAS();
        ]]>
    </mx:Script>

    <mx:Label x="10" y="68" text="Vorname"/>
    <mx:TextInput x="178" y="92" id="textinput1"/>
    <mx:Label x="178" y="66" text="Name" id="label1"/>
    <mx:Label x="10" y="10" text="Anrede" id="label2"/>
    <mx:TextInput x="10" y="94" id="textinput3"/>
    <mx:TextInput x="178" y="148" width="48" id="textinput2"/>
    <mx:TextInput x="234" y="148" width="104"/>
    <mx:TextInput x="10" y="150" id="textinput0"/>
    <mx:Label x="10" y="124" text="Straße" id="label0"/>
    <mx:Label x="10" y="180" text="Geburtsdatum"/>
    <mx:DateField x="10" y="206" width="160"/>
    <mx:Label x="234" y="124" text="Ort"/>
    <mx:Label x="178" y="124" text="PLZ"/>
    <mx:Label x="10" y="236" text="Telefon (privat)"/>
    <mx:TextInput x="10" y="262" id="textinput5"/>
    <mx:TextInput x="178" y="262" id="textinput6"/>
    <mx:Label x="178" y="236" text="Telefon (geschäftlich)"/>
    <mx:TextInput x="178" y="206" id="textinput7"/>
    <mx:Label x="178" y="180" text="E-Mail"/>
    <mx:Label x="10" y="292" text="Anmerkungen"/>
    <mx:Button x="256" y="392" label="Speichern" click="_AddCustomersAS.sendForm()"/>
    <mx:ComboBox x="10" y="36" selectedIndex="0">
        <mx:ArrayCollection>
            <mx:Object label="Herr" data="m"/>
            <mx:Object label="Frau" data="w"/>
        </mx:ArrayCollection>
    </mx:ComboBox>
    <mx:TextArea x="10" y="318" width="328" height="66"/>

</mx:Canvas>
Last but not least, der AS3 Code hinter der Komponente (diese Klasse wird im "Script" Teil des MXML Dokumentes implementiert:

PHP-Code:
package lib.components
{
    
import mx.controls.Alert;
    
    public class 
AddCustomersAS
    
{
        
        public function 
sendForm():void {
            
Alert.show("Senden des Formulars","Absenden");
            
            
textinput1.text "OK";
        }
    }

Die Verständnissfrage die ich habe betrifft die letzte Zeile, nämlich "textinput1.text = "OK";"

Warum kann ich vom Action Script File der Komponente nicht auf die Felder in der Komponente zugreifen. Bzw. wie könnte ich im ActionScript File der Komponente auf die "Hauptbühne", also meine Main Applikation, zugreifen? Wie geht das?

Grüße Christian
Utopian ist offline   Mit Zitat antworten
Alt 09-12-2007, 17:45   #2 (permalink)
-
 
Registriert seit: Jul 2003
Beiträge: 714
So wie ich das sehe erzeugst du eine MXML Komponente (lib.components.AddCustomers) .
Code:
<mx:Canvas>
...
</mx:Canvas>
Und in dem Skript Tag von dieser Komponenten erzeugst du eine Instanz der Klasse AddCustomersAS.
Code:
<mx:Script> 
        <![CDATA[ 
            import lib.components.AddCustomersAS; 
            public var _AddCustomersAS:AddCustomersAS = new AddCustomersAS(); 
        ]]> 
    </mx:Script>
Und innerhalb dieser Klasse (AddCustomersAS), die nichts mit der MXML - Komponente zu tun hat, willst du auf eine Eigenschaft der MXML - Komponente zugreifen.
Richtig?

Wenn ja:
So kann das nicht klappen. Die Klasse AddCustomersAS ist doch keine Unterklasse von AddCustomers, so dass ein Zugriff auf die Instanzvariabel der MXML - Komponente nicht möglich ist.

Lösung 1 wäre das du die Funktion sendForm() einfach in den Skript Tag der MXML-Komponente, die eine Klasse darstellt, packst.
Oder, Lösung 2, das du halt eine Referenz auf die Komponenten bei der Klasseninitialisierung von AddCustomersAS mitgibst.

Ich glaube du verstehst wohl noch nicht das MXML - Komponenten ganz normale Klassen sind.
messingfeld ist offline   Mit Zitat antworten
Alt 09-12-2007, 18:18   #3 (permalink)
Nagelneuer User
 
Benutzerbild von hazy fantazy
 
Registriert seit: Dec 2005
Beiträge: 924
Der Trick ist, ein Binding zu benutzen.

Leg in der AS Klasse eine property textinput an,
[Bindable] public var textinput : String;
und verknüpfe sie in mxml per Binding
<mx:TextInput text="{_AddCustomersAS.textinput}" ... />

_AddCustomersAS muss natürlich auch bindable sein.

Auf die Art hast du Präsentation und Logik schön voneinander getrennt,
denn durch das Binding muss die Logik gar nichts vom View wissen.
Wenn du das konsequent durchziehst, kannst du die komplette Logik
per FlexUnit testen, ohne auch nur eine einzige Ui Komponente erzeugen zu müssen.

Code:
public function testSendFormSetsTextToOK() : void
{
     //setup fixture
     var model : AddCustomersAS = new AddCustomersAS();

     //execute test
     model.sendForm();

     //check results
     assertEquals( "OK", model.textinput );
}
__________________
The fact that you've got "Replica" written on the side of your gun and the fact that I've got "Desert Eagle written on the side of mine ... :D

Geändert von hazy fantazy (09-12-2007 um 18:42 Uhr)
hazy fantazy ist offline   Mit Zitat antworten
Alt 09-12-2007, 22:37   #4 (permalink)
Neuer User
 
Benutzerbild von Utopian
 
Registriert seit: May 2003
Beiträge: 1.031
Zitat:
Zitat von hazy fantazy Beitrag anzeigen
Der Trick ist, ein Binding zu benutzen.

Leg in der AS Klasse eine property textinput an,
[Bindable] public var textinput : String;
und verknüpfe sie in mxml per Binding
<mx:TextInput text="{_AddCustomersAS.textinput}" ... />

_AddCustomersAS muss natürlich auch bindable sein.

Auf die Art hast du Präsentation und Logik schön voneinander getrennt,
denn durch das Binding muss die Logik gar nichts vom View wissen.
Wenn du das konsequent durchziehst, kannst du die komplette Logik
per FlexUnit testen, ohne auch nur eine einzige Ui Komponente erzeugen zu müssen.

Code:
public function testSendFormSetsTextToOK() : void
{
     //setup fixture
     var model : AddCustomersAS = new AddCustomersAS();

     //execute test
     model.sendForm();

     //check results
     assertEquals( "OK", model.textinput );
}
Hallo,

hm verstehe, das macht Sinn. Allerdings sagt das MXML nun:

PHP-Code:
Data binding will not be able to detect assignments to "_AddCustomersAS"
Von AS Seite kann ich auch nicht auf die Variable zugreifen. Was mache ich falsch?

Danke

Grüße Christian
Utopian ist offline   Mit Zitat antworten
Alt 09-12-2007, 23:05   #5 (permalink)
Neuer User
 
Benutzerbild von Utopian
 
Registriert seit: May 2003
Beiträge: 1.031
Das funktioniert innerhalb der MXML Komponente:

PHP-Code:
    <mx:Label x="10" y="68" text="Vorname"/>
    <
mx:TextInput x="10" y="92" id="firstname" change="{_AddCustomersAS.firstname=this.firstname.text}" /> 
So wie ich das verstehe, mappe ich das "change" Event der TextInput Komponente in meiner eigenen Komponente auf die Instanz der Klasse.

In der AS Klasse habe ich dann eine public variable Namens "firstname":

PHP-Code:
public var firstname:String
Das geht sogar ohne Bindable. Aber ist das der richtige Weg? Benötigt wahrscheinlich mehr Performance wenn jedes mal ein "change" Event abgefeuert wird als wenn ich bindable benutze oder?

Grüße Christian
Utopian ist offline   Mit Zitat antworten
Alt 10-12-2007, 07:55   #6 (permalink)
Perverted Hermit
 
Benutzerbild von Omega Psi
 
Registriert seit: Mar 2004
Ort: Delmenhorst
Beiträge: 12.142
Das ist der richtige Weg. DataProvider feuern theoretisch auch unentwegt und wenn du dir mal ein paar Listenerausgaben von Trees oder anderen Komponenten ausgeben lässt, dann wirst du sehen das Events sehr effektiv sind. Die meisste Zeit für Rechenoperationen geht für das Rendering druff...
Omega Psi ist offline   Mit Zitat antworten
Alt 10-12-2007, 08:08   #7 (permalink)
Neuer User
 
Benutzerbild von Utopian
 
Registriert seit: May 2003
Beiträge: 1.031
Zitat:
Zitat von Omega Psi Beitrag anzeigen
Das ist der richtige Weg. DataProvider feuern theoretisch auch unentwegt und wenn du dir mal ein paar Listenerausgaben von Trees oder anderen Komponenten ausgeben lässt, dann wirst du sehen das Events sehr effektiv sind. Die meisste Zeit für Rechenoperationen geht für das Rendering druff...
Danke!

Trotzdem die Frage: "Bindable" oder "Listener"?

Grüße Christian
Utopian ist offline   Mit Zitat antworten
Alt 10-12-2007, 08:19   #8 (permalink)
Perverted Hermit
 
Benutzerbild von Omega Psi
 
Registriert seit: Mar 2004
Ort: Delmenhorst
Beiträge: 12.142
Wenn du Bindable verwendest, erzeugst du implizit einen Listener.

Als Beispiel könnte man wieder eine ArrayCollection oder XMLListCollection nehmen. Die informieren ihre Views auch automatisch, wenn die als DataProvider bei ihnen angemeldet sind. Die Collections feuern bei jeder Änderung ein CollectionEvent.COLLECTION_CHANGE. Durch die [Bindable] Deklaration werden im Framework die entsprechenden EventListener erzeugt.
Omega Psi ist offline   Mit Zitat antworten
Alt 10-12-2007, 08:34   #9 (permalink)
Nagelneuer User
 
Benutzerbild von hazy fantazy
 
Registriert seit: Dec 2005
Beiträge: 924
Es gibt hier zwei Richtungen.

Von der AS Klasse (dem Model) in die MXML Klasse (den View) benutzt du Binding. Damit kannst du z.B. die Texteigenschaft eines Textfelds aus deinem Model heraus ändern, wie in meinem ersten Posting beschrieben.

Umgekehrt, also vom View zum Model benutzt du Listener. Das wäre dann dein letztes Beispiel. Normalerweise würde ich allerdings eine Methode aufrufen, anstatt eine Eigenschaft des Models direkt zu verändern. Sowas in der Art: ... change="_AddCustomersAS.handleChangeFirstName( event.target.text )" ...

Damit die Compilerwarnung verschwindet, musst du _AddCustomersAS auch Bindable machen,
__________________
The fact that you've got "Replica" written on the side of your gun and the fact that I've got "Desert Eagle written on the side of mine ... :D

Geändert von hazy fantazy (10-12-2007 um 10:18 Uhr)
hazy fantazy ist offline   Mit Zitat antworten
Alt 10-12-2007, 08:47   #10 (permalink)
Perverted Hermit
 
Benutzerbild von Omega Psi
 
Registriert seit: Mar 2004
Ort: Delmenhorst
Beiträge: 12.142
Der Listener ist der Controller, um im MVC zu bleiben. Du brauchst den Controller um die Benachrichtigungen von der View zum Model zu schicken.

Du könntest, um die View zu aktualisieren auch Events explizit feuern und entsprechende EventListener an Views/View-Komponenten registrieren. Die [Bindable] Deklaration nimmt dir diese Arbeit ab.

[Bindable] setzt aber vorraus, dass die Klasse, deren Felder mit Views assoziiert sind als [Bindable] und public deklariert sind, oder das Felder direkt als [Bindable] und public deklariert sind oder implizite get und set Methoden verwendet werden. Diese müssen auch als [Bindable] und public deklariert sein. Ausserdem müssen die Instanzen/Referenzen auf die Instanzen in den jeweilige Scopes auch als [Bindable] deklariert sein.

Ich benutze die version mit den impliziten get und set Methoden:
ActionScript:
  1. /**
  2. * @author Psi, Omega
  3. * @version 0.0.0.0.0.1
  4. *
  5. * Created with BeanButler © 2007, Omega Psi
  6. */
  7. package {
  8.     [Bindable] public class Person {
  9.         private var _name:String;
  10.         public function Person() {
  11.         }
  12.         public function get name():String {
  13.             return this._name;
  14.         }
  15.         public function set name(name:String):void {
  16.             this._name = name;
  17.         }
  18.         public function toString():String {
  19.             var asString:String = "Person#toString";
  20.             asString += "\n\t- name: "+this._name;
  21.             return asString;
  22.         }
  23.     }
  24. }
Dadurch kann man die Klasse [Bindable] deklarieren und gleichzeitig eine vernünftige Kapselung der Daten garantieren.

Geändert von Omega Psi (10-12-2007 um 08:49 Uhr)
Omega Psi ist offline   Mit Zitat antworten
Alt 10-12-2007, 09:32   #11 (permalink)
Neuer User
 
Benutzerbild von Utopian
 
Registriert seit: May 2003
Beiträge: 1.031
Danke euch beiden! Das hat mir geholfen MVC besser zu verstehen.

Ich wußte nicht das man ganze Klassen als Bindable definieren kann.

Ich melde mich heute Abend sicherlich noch mal wenn ich alles
Testen konnte was ihr mir hier angeboten habt.

Besten Dank erst mal für eure Mühe!

Grüße Christian
Utopian ist offline   Mit Zitat antworten
Alt 26-09-2008, 08:30   #12 (permalink)
reXcel
 
Benutzerbild von Sören
 
Registriert seit: Aug 2002
Ort: Herford
Beiträge: 4.774
Ich habe eine ähnliche Verständnisfrage - verstehe den richtigen Weg aber noch nicht.

Beispiel: VideoDisplay Komponente
Normal eingebunden und z.B. mit der ID 'video' versehen.

Ich möchte nun von verschiedenen Komponenten/Klassen aus die sich im Projekt befinden auf die Variable 'source' des VideoDisplay zugreifen... also ein Video zuordnen.

- Wie mache ich das dann am besten per AS?
- Und wie am besten per MXML?
__________________
iPhone, iPad, Android und Flash Video Streamingserver
Streaming & Live-Streaming für Flash, iPhone, iPad, iPod touch und Android.
Inkl. Player, Videokonvertierung in optimierte Formate, Playercode, Flexplayer, etc...
Sören ist offline   Mit Zitat antworten
Alt 26-09-2008, 09:12   #13 (permalink)
Perverted Hermit
 
Benutzerbild von Omega Psi
 
Registriert seit: Mar 2004
Ort: Delmenhorst
Beiträge: 12.142
Wenn du eine id in einem MXML Knoten vergeben hast, kannst du via Punkt-Notation drauf zugreifen (dich wie bei allen Pfaden durchpunkten). In ActionScript würde ich eine get-Funktion schreiben.
Omega Psi ist offline   Mit Zitat antworten
Alt 26-09-2008, 09:33   #14 (permalink)
reXcel
 
Benutzerbild von Sören
 
Registriert seit: Aug 2002
Ort: Herford
Beiträge: 4.774
Hi Florian,
das kommt mir aber so "quick&dirty" vor. Zudem ist es übelst unflexibel wenn das Projekt mal umgestrickt wird.

Da gefällt mir das DataBinding schon besser. Doch hier habe ich den Dreh noch nicht verstanden.

- Binding innerhalb einer Komponente ist kein Problem.
- Auch kann ich auf die Eigenschaften von Instanzen zugreifen, die ich in der Komponente/Klasse gerade selber erzeugt habe.

- Doch wenn ich z.B. in Main eine XX Klasse einbinde (bzw. Instanz erzeuge) und dann noch eine Klasse/Instananz ZZ. Und nun möchte ich von ZZ aus auf XX zugreifen... da erhalte ich Fehlermeldungen. Und da habe ich scheinbar ein Brett vor dem Kopf. Ich denke mal es ist nur eine Zeile Code die mir fehlt ..
__________________
iPhone, iPad, Android und Flash Video Streamingserver
Streaming & Live-Streaming für Flash, iPhone, iPad, iPod touch und Android.
Inkl. Player, Videokonvertierung in optimierte Formate, Playercode, Flexplayer, etc...

Geändert von Sören (26-09-2008 um 09:36 Uhr)
Sören ist offline   Mit Zitat antworten
Alt 26-09-2008, 09:45   #15 (permalink)
Perverted Hermit
 
Benutzerbild von Omega Psi
 
Registriert seit: Mar 2004
Ort: Delmenhorst
Beiträge: 12.142
Durchpunkten ist auch quick'n dirty...

Um ein eigenes DataBinding zu ermöglichen:
ActionScript:
  1. private var _myProperty:String;
  2.  
  3. [Bindable("myPropertyChanged")]
  4. public function get myProperty():String {
  5.     return this._myProperty;
  6. }
  7.  
  8. public function set myProperty(value:String):void {
  9.     if (this._myProperty == value) {
  10.         return;
  11.     }
  12.     this._myProperty = value;
  13.     this.dispatchEvent(new Event("myPropertyChanged"));
  14. }
Aber letzten Endes läuft das ganze dann auch über den getter, nur das du die Änderungen automatisch mitbekommst.

Ich würde die Instanzen via get/set durch die Objekthierarchien durchreichen. Wenn die Hierachien zu tief sind, mag die Struktur für deine Belange nicht optimal sein und es bedarf etwas Nacharbeit...

Du kannst auch über über einen get Accessor einer Klasse auf andere getter deligieren:
ActionScript:
  1. /* Offers custom databinding */
  2. [Bindable("bestFriendChanged")]
  3. private var _bestFriend:IFriend;
  4. function get bestFriendsName():String {
  5.     return this. _bestFriend.name;
  6. }
Da gibt es einige Methoden, das zu erreichen.
Omega Psi ist offline   Mit Zitat antworten
Antwort

Lesezeichen

Stichworte
as3, komponente, mxml

Themen-Optionen
Ansicht

Forumregeln
Es ist Ihnen nicht erlaubt, neue Themen zu verfassen.
Es ist Ihnen nicht erlaubt, auf Beiträge zu antworten.
Es ist Ihnen nicht erlaubt, Anhänge hochzuladen.
Es ist Ihnen nicht erlaubt, Ihre Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks sind an
Pingbacks sind an
Refbacks sind an



Alle Zeitangaben in WEZ +1. Es ist jetzt 04:29 Uhr.

Domains, Webhosting & Vserver von Host Europe
Unterstützt das Flashforum!
Adobe User Group


Copyright ©1999 – 2012 Marc Thiele