Uma das melhores idéias do Flex, e o que o torna bastante produtivo na minha opinião é a existencia de uma “linguagem” para layout de telas, é o tal de MXML.
Claro que eu sei que é apenas XML, mas é XML com acesso direto as classes existentes e recem criadas, e uma mão na roda para separar o código do layout, facilitando bastante a escrita de código MVC compliant.
O maior problema da arquitetura básica do Flex é não ser “óbvio” como escrever o código de tratamento dos eventos gerados sem poluir o MXML com muitas tags “mx:Script” e muito código ActionScript.
Claro que existem alguns frameworks para o desenvolvimento de aplicações Flex como o Cairngorm e o PureMVC, mas algumas vezes estes frameworks mais complicam do que ajudam, e mesmo utilizando um deles, esta dica que vou apresentar agora de como simular o “code behind” do “.NET” em flex pode ser utilizada sem maiores problemas …
A idéia principal é separa o código ActionScript do código XML, como se fosse uma “partial class” do “.NET”, o Flex não suporta Partial Classes, mas suporta herança, e podemos tirar proveito disto …
Vou mostrar um exemplo bastante simplista aqui, apenas para que vocês peguem a idéia, vejam o código da tela abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <?xml version="1.0" encoding="utf-8"?> <mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%"> <mx:Script> <![CDATA[ import mx.controls.DataGrid; import mx.events.ListEvent; [Bindable] private var current : Object = new Object(); [Bindable] private var all : Array = []; private function saveCurrent(nome : String, idade : Number) : void { var obj : Object = {nome : nome, idade : idade, id : all.length + 1}; var temp : Array = all.slice(0,all.length); temp.push(obj); all = temp; current = obj; } private function updateCurrent(nome : String, idade : Number) : void { current.nome = nome; current.idade = idade; } private function newCurrent() : void { current = new Object(); } private function selectionChange(evt : ListEvent) : void { current = (evt.target as DataGrid).selectedItem; } ]]> </mx:Script> <mx:Label fontSize="24" width="100%" textAlign="center" text="Cadastro de Pessoas"/> <mx:HBox width="100%"> <mx:Label text="Nome:" width="100"/> <mx:TextInput id="currentNome" text="{current.nome}"/> </mx:HBox> <mx:HBox width="100%"> <mx:Label text="Idade:" width="100"/> <mx:NumericStepper id="currentIdade" value="{current.idade}" minimum="5" maximum="150"/> </mx:HBox> <mx:HBox width="100%" horizontalAlign="center"> <mx:Button label="Salvar" click="saveCurrent(currentNome.text,currentIdade.value)" enabled="{!current.id}"/> <mx:Button label="Novo" click="newCurrent()" enabled="{current.id}"/> <mx:Button label="Atualizar" click="updateCurrent(currentNome.text,currentIdade.value)" enabled="{current.id}"/> </mx:HBox> <mx:DataGrid width="100%" dataProvider="{all}" change="selectionChange(event)"> <mx:columns> <mx:DataGridColumn headerText="Id" dataField="id"/> <mx:DataGridColumn headerText="Nome" dataField="nome"/> <mx:DataGridColumn headerText="Idade" dataField="idade"/> </mx:columns> </mx:DataGrid> </mx:VBox> |
Apenas para este bastatne simples, já temos quase metade do arquivo contendo ActionScript e metade contendo MXML.
Em um caso simples destes isto não chega a incomodar, mas quando o arquivo começa a crescer, isto atrapalha a leitura do código fonte, o que é bastante ruim. Então a minha sugestão, ou “dica” de como resolver isto, é separar o código ActionScript em um arquivo .as e manter apenas o layout no arquivo MXML, como pode ser visto no seguinte exemplo (considerando que o nome do arquivo mostrado acima seja telaexemplo.mxml)
Criar a classe “exemplo.TelaExemploBase” no diretório correspondente com o seguinte código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | package exemplo { import mx.containers.VBox; import mx.controls.DataGrid; import mx.events.ListEvent; public class TelaExemploBase extends VBox { [Bindable] protected var current : Object = new Object(); [Bindable] protected var all : Array = []; public function TelaExemploBase() { super(); } protected function saveCurrent(nome : String, idade : Number) : void { var obj : Object = {nome : nome, idade : idade, id : all.length + 1}; var temp : Array = all.slice(0,all.length); temp.push(obj); all = temp; current = obj; } protected function updateCurrent(nome : String, idade : Number) : void { current.nome = nome; current.idade = idade; } protected function newCurrent() : void { current = new Object(); } protected function selectionChange(evt : ListEvent) : void { current = (evt.target as DataGrid).selectedItem; } } } |
Alterar o arquivo MXML para o seguinte código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?xml version="1.0" encoding="utf-8"?> <TelaExemploBase xmlns="exemplo.*" xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" > <mx:Label fontSize="24" width="100%" textAlign="center" text="Cadastro de Pessoas"/> <mx:HBox width="100%"> <mx:Label text="Nome:" width="100"/> <mx:TextInput id="currentNome" text="{current.nome}"/> </mx:HBox> <mx:HBox width="100%"> <mx:Label text="Idade:" width="100"/> <mx:NumericStepper id="currentIdade" value="{current.idade}" minimum="5" maximum="150"/> </mx:HBox> <mx:HBox width="100%" horizontalAlign="center"> <mx:Button label="Salvar" click="saveCurrent(currentNome.text,currentIdade.value)" enabled="{!current.id}"/> <mx:Button label="Novo" click="newCurrent()" enabled="{current.id}"/> <mx:Button label="Atualizar" click="updateCurrent(currentNome.text,currentIdade.value)" enabled="{current.id}"/> </mx:HBox> <mx:DataGrid width="100%" dataProvider="{all}" change="selectionChange(event)"> <mx:columns> <mx:DataGridColumn headerText="Id" dataField="id"/> <mx:DataGridColumn headerText="Nome" dataField="nome"/> <mx:DataGridColumn headerText="Idade" dataField="idade"/> </mx:columns> </mx:DataGrid> </TelaExemploBase> |
A idéia básica é utilizar o MXML para extender a classe ActionScript que contem o código, a diferença é que tudo o que deve ser acessado do MXML na classe criada não pode ser privado, tem que ser no mínimo protected (o que foi utilizado no exemplo).
Outro truque é definir o “xmlns” para o pacote da classe que vai ser extendida como pode ser visto na linha 2.
E para testar isto é necessária uma “aplicação flex”, eu utilizei apenas o código abaixo para o projeto de testes:
1 2 3 4 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*"> <local:telaexemplo width="100%" height="100%"/> </mx:Application> |
Mas claro que você pode fazer algo mais elaborado
Espero que esta dica ajude alguem, ja que eu tive bastante trabalho reorganizando código depois que descobri que isto era muito melhor do que colocar tudo no MXML logo que comecei a trabalhar com Flex.
If you enjoyed this post, make sure you subscribe to my RSS feed!
Urubatan,
Ótima dica. Eu já conhecia a forma mais simples de dividir o ActionScript através de , mas da forma que tu indicou é extremamente mais elegante.
Muito bom!!!! Valeu!!!
[]´s
[Translate]
Muito bom cara… Ótima dica!
[Translate]
Muito boa essa dica Urubatan…
Eu comecei a separar o código mxml e ActionScript mas não gostei quando tinha que manipular um componente mxml no ActionScript. Essa situação ocorre com muita freqüência. Como vc faria???
Abraços!
[Translate]
Muito legal seu exemplo Urubatan, estou implementando algo semelhante aqui porém estou com um problema! Como você faz para acessar os componentes da view? por exemplo um combobox à partir do “.as” sem ter que declará-lo nele? O contrário eu ví que é perfeitamente possível.
Valew!
[Translate]
O contrario não é possível, então você tem que organizar o seu código para que isto não seja um problema, como você pode ver no exemplo, onde eu utilizo um evento para acessar um DataGrid da view. Ou seja, é só passar o objeto como parâmetro para algum método
[Translate]
Muito bom! Teria como citar um exemplo de como acessar do .as os componentes do .mxml
Tipo pegar o valor do id=”currentNome”
[Translate]
Urubatan,
Massa cara.
Mas no meu MXML, tenho uma chamada para uma função que está nesse arquivo .as. O que devo fazer?
[Translate]
nem tanto ao céu nem tanto a terra
Claro que no MXML tu vai ter que chamar os métodos definidos no as, mas sem exageros
[Translate]
Entendo.
Na verdade agora vi que a pergunta foi um tanto quanto muito burra hehehe. lol
Mas eu as o MXML aparentemente não encontra o classe com os eventos. Eu crio uma pasta dentre da minha pasta de componentes e faço o que você fez ali (com o package events e tudo mais). E na hora de “importar” para o MXML, eu coloco só o xmlns. Eu estou fazendo alguma coisa fora do normal?
Abraço.
[Translate]
Ótimo artigo ! Muito grato pela sua iniciativa de compartilhar seu conhecimento, parabéns.
[Translate]