14. A aplicação [SimuPaie] – versão 10 – cliente Flex de um serviço web ASP.NET
Apresentamos agora um cliente Flex do serviço web ASP.NET da versão 5. O IDE utilizado é o Flex Builder 3. Uma versão de demonstração deste produto pode ser baixada no URL [https://www.adobe.com/cfusion/tdrc/index.cfm?loc=fr_fr&product=flex]. O Flex Builder 3 é um IDE Eclipse. Além disso, para executar o cliente Flex, utilizamos um servidor web Apache da ferramenta Wamp [http://www.wampserver.com/]. Qualquer servidor Apache serve. O navegador que exibe o cliente Flex deve ter o plug-in Flash Player, versão 9 no mínimo.
As aplicações Flex têm a particularidade de serem executadas dentro do plug-in Flash Player do navegador. Nesse aspecto, elas se assemelham às aplicações Ajax, que incorporam nas páginas enviadas ao navegador scripts JavaScript que são, em seguida, executados dentro do navegador. Uma aplicação Flex não é uma aplicação web no sentido em que normalmente se entende: é uma aplicação cliente de serviços fornecidos por servidores web. Nesse aspecto, ela é análoga a uma aplicação de desktop que seria cliente desses mesmos serviços. No entanto, ela difere em um ponto: é baixada inicialmente de um servidor web para um navegador que possua o plug-in Flash Player capaz de executá-la.
Assim como um aplicativo de desktop, um aplicativo Flex é composto principalmente por dois elementos:
- uma parte de apresentação: as visualizações exibidas no navegador. Essas visualizações possuem a riqueza das janelas dos aplicativos de desktop. Uma visualização é descrita por meio de uma linguagem de marcação chamada MXML.
- uma parte de código que gerencia principalmente os eventos provocados pelas ações do usuário na visualização. Esse código também pode ser escrito em MXML ou em uma linguagem orientada a objetos chamada ActionScript. É preciso distinguir dois tipos de eventos:
- o evento que requer uma troca de dados com o servidor web: preenchimento de uma lista com dados fornecidos por um aplicativo web, envio dos dados de um formulário ao servidor, etc. O Flex fornece vários métodos para se comunicar com o servidor de forma transparente para o desenvolvedor. Esses métodos são, por padrão, assíncronos: o usuário pode continuar interagindo com a visualização durante a solicitação ao servidor.
- o evento que altera a visualização exibida sem troca de dados com o servidor, por exemplo, arrastar um elemento de uma árvore para soltá-lo em uma lista. Esse tipo de evento é totalmente processado localmente no navegador.
Um aplicativo Flex é frequentemente executado da seguinte maneira:
![]() |
- em [1], uma página HTML é solicitada
- em [2], ela é enviada. Ela traz consigo um arquivo binário SWF (ShockWave Flash) contendo a aplicação Flex na íntegra: todas as visualizações e o código de gerenciamento de eventos delas. Esse arquivo será executado pelo plug-in Flash Player do navegador.
![]() |
- A execução do cliente Flex ocorre localmente no navegador, exceto quando ele precisa de dados externos. Nesse caso, ele os solicita ao servidor [3]. Ele os recebe no formato [4], em diversos formatos: XML ou binário. O aplicativo consultado no servidor web pode ser escrito em qualquer linguagem. O que importa é apenas o formato da resposta.
Descrevemos a arquitetura de execução de um aplicativo Flex para que o leitor perceba a diferença entre ela e a de um aplicativo web clássico, no qual as páginas não contêm código (JavaScript, Flex, Silverlight, etc.) que o navegador executaria. Nesta última, o navegador é passivo: ele simplesmente exibe páginas HTML criadas no servidor web, que as envia para ele.
14.1. Arquitetura do aplicativo cliente/servidor
A arquitetura cliente/servidor implementada é semelhante à das versões 6 e 8:
![]() |
No [1], a camada web ASP.NET é substituída por uma camada web Flex escrita em MXML e ActionScript. O cliente [C] será gerado pelo Flex Builder IDE. É importante lembrar aqui que essa arquitetura inclui dois servidores web não representados:
- um servidor web ASP.NET que executa o serviço web [S]
- um servidor web APACHE que executa o cliente web [1]
14.2. O projeto Flex 3 do cliente
Estamos desenvolvendo o cliente Flex com o Flex Builder 3 IDE:
![]() |
- no Flex Builder 3, criamos um novo projeto em [1]
- damos um nome a ele em [2] e especificamos em [3] em qual pasta ele deve ser gerado
![]() |
- em [4], atribui-se um nome ao aplicativo principal (aquele que será executado)
- em [5], o projeto, uma vez gerado
- em [6], o arquivo principal da aplicação MXML
- um arquivo MXML contém uma visualização e o código de gerenciamento de eventos correspondente. A guia [Source] [7] dá acesso ao arquivo MXML. Nele, encontram-se as tags <mx> que descrevem a visualização, bem como o código ActionScript.
- A visualização pode ser criada graficamente usando a aba [Design] [8]. As tags MXML que descrevem a visualização são, então, geradas automaticamente na aba [Source]. O inverso também é verdadeiro: as tags MXML adicionadas diretamente na guia [Source] são refletidas graficamente na guia [Design].
14.3. A visualização nº 1
Vamos construir, passo a passo, uma interface web semelhante à da versão 1 (ver parágrafo 4). Primeiro, vamos construir a seguinte interface:
![]() |
- em [1], a tela exibida quando a conexão com o serviço web foi estabelecida. A lista suspensa dos funcionários é então preenchida.
- em [2], a tela exibida quando não foi possível estabelecer a conexão com o serviço web. Nesse caso, é exibida uma mensagem de erro.
O arquivo principal do cliente, [main.xml], é o seguinte:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
creationComplete="init()">
<mx:VBox width="100%">
<mx:Label text="Feuille de salaire" fontSize="30"/>
<mx:HBox>
<mx:VBox>
<mx:Label text="Employés"/>
<mx:ComboBox id="cmbEmployes" dataProvider="{employes}" labelFunction="displayEmploye"/>
</mx:VBox>
<mx:VBox>
<mx:Label text="Heures travaillées"/>
<mx:TextInput id="txtHeuresTravaillees"/>
</mx:VBox>
<mx:VBox>
<mx:Label text="Jours travaillés"/>
<mx:NumericStepper id="joursTravailles" minimum="0" maximum="31" stepSize="1"/>
</mx:VBox>
<mx:VBox>
<mx:Label text=""/>
<mx:Button id="btnSalaire" label="Salaire"/>
</mx:VBox>
</mx:HBox>
<mx:TextArea id="msg" minWidth="400" minHeight="100" editable="false" visible="true" enabled="true" horizontalScrollPolicy="auto" verticalScrollPolicy="auto" x="0" y="0" maxHeight="100" maxWidth="400"/>
</mx:VBox>
<mx:WebService ...>
...
</mx:WebService>
<mx:Script>
<![CDATA[
...
// dados
[Bindable]
private var employes : ArrayCollection;
private function init():void{
...
}
]]>
</mx:Script>
</mx:Application>
Nesse código, é preciso distinguir vários elementos:
- a definição do aplicativo (linhas 2-3)
- a descrição da visualização da aplicação (linhas 4-25)
- os manipuladores de eventos na linguagem ActionScript dentro da tag <mx:Script> (linhas 31-42).
- a definição do serviço web remoto (linhas 27-29)
Vamos começar comentando a definição da própria aplicação e a descrição de sua visualização:
- linhas 2-3: definem:
- o modo de disposição dos componentes no contêiner da visualização. O atributo layout="vertical" indica que os componentes ficarão uns abaixo dos outros.
- o método a ser executado quando a visualização for instanciada, c.a.d. o momento em que todos os seus componentes tiverem sido instanciados. O atributo creationComplete="init();" indica que o método init da linha 38 deve ser executado. creationComplete é um dos eventos que a classe Application pode emitir.
- as linhas 4 a 25 definem os componentes da visualização
- linhas 4 a 25: um contêiner vertical; os componentes serão posicionados uns abaixo dos outros
- linha 5: define um texto
- linhas 6 a 23: um contêiner horizontal: os componentes serão posicionados horizontalmente nele.
- linhas 7 a 10: um contêiner vertical que conterá um texto e uma lista suspensa
- linha 8: o texto
- linha 9: a lista suspensa na qual será inserida a lista de funcionários. A tag dataProvider="{employes}" indica a fonte dos dados que devem preencher a lista. Aqui, a lista será preenchida com o objeto employes definido na linha 36. Para poder escrever dataProvider="{employes}", é necessário que o campo employes tenha o atributo [Bindable] (linha 35). Esse atributo permite que uma variável ActionScript seja referenciada fora da tag <mx:Script>. O campo employes é do tipo ArrayCollection, um tipo ActionScript que permite armazenar listas de objetos, neste caso, uma lista de objetos do tipo Employe.
- linhas 11-14: um contêiner vertical que conterá um texto e um campo de entrada
- linha 12: o texto
- linha 13: o campo de preenchimento das horas trabalhadas.
- linhas 15-18: um contêiner vertical que conterá um texto e um contador
- linha 16: o texto
- linha 17: o contador que permitirá a inserção dos dias trabalhados.
- linhas 19-22: um contêiner vertical que conterá um texto e um botão que acionará o cálculo do salário da pessoa selecionada na lista suspensa.
- linha 20: o texto
- linha 21: o botão.
- linha 23: fim do contêiner horizontal iniciado na linha 6
- linha 24: uma área de texto em um componente do tipo TextArea. Ela exibirá as mensagens de erro.
- linha 25: fim do contêiner vertical iniciado na linha 4
As linhas 4 a 25 geram a seguinte visualização na guia [Design]:
![]() |
- [1]: foi gerado pelo componente Label da linha 5
- [2]: foi gerado pelo componente ComboBox da linha 9
- [3]: foi gerado pelo componente TextInput da linha 13
- [4]: foi gerado pelo componente NumericStepper da linha 17
- [5]: foi gerado pelo componente Button da linha 21
- [6]: foi gerado pelo componente TextArea da linha 24
Vamos agora examinar a declaração do serviço web remoto:
<mx:WebService id="pam"
wsdl="http://localhost:1077/Service1.asmx?WSDL"
fault="wsFault(event);"
showBusyCursor="true">
<mx:operation
name="GetAllIdentitesEmployes"
result="loadEmployesCompleted(event)"
fault="loadEmployesFault(event);">
<mx:request/>
</mx:operation>
</mx:WebService>
- linha 1: o serviço web é um componente com o identificador pam (atributo id)
- linha 2: o URI do arquivo WSDL do serviço web (ver parágrafo 9.2)
- linha 3: o método a ser executado em caso de erro durante as trocas de dados com o serviço web: o método wsFault.
- linha 4: solicita que um indicador seja exibido para mostrar ao usuário que uma comunicação com o serviço web está em andamento.
- linhas 5-10: uma das operações oferecidas pelo serviço web remoto. Neste caso, o método GetAllIdentitesEmployes.
- linha 7: o método a ser executado quando a chamada desse método for concluída normalmente, c.a.d. Quando o serviço web retorna corretamente a lista de funcionários
- linha 8: o método a ser executado quando a chamada desse método terminar com um erro.
- linha 9: os parâmetros da operação GetAllIdentitesEmployes. Sabemos que esse método não espera parâmetros. Portanto, deixamos a tag <mx:request> vazia.
Vamos agora examinar o código ActionScript relacionado ao serviço web:
<mx:Script>
<![CDATA[
import mx.rpc.events.FaultEvent;
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
// dados
[Bindable]
private var employes : ArrayCollection;
private function init():void{
// anotam-se as coordenadas da área de mensagem
msgHeight=msg.height;
msgWidth=msg.width;
// ocultamos a área de mensagem
hideMsg();
// solicitação ao serviço web remoto para obter a lista simplificada de funcionários
pam.GetAllIdentitesEmployes.send();
}
private function wsFault(event:Event):void{
// é sinalizado o erro
msg.text="Service distant indisponible";
showMsg();
}
private function loadEmployesCompleted(event:ResultEvent):void{
// preenchimento da lista suspensa de funcionários
employes=event.result as ArrayCollection;
}
private function displayEmploye(employe:Object):String{
// identidade de um funcionário
return employe.Prenom + " " + employe.Nom;
}
private function loadEmployesFault(event:FaultEvent):void{
// exibição da mensagem de erro
msg.text=event.fault.message;
// formulário
showMsg();
}
// gerenciamento de blocos
private var msgWidth:int;
private var msgHeight:int;
private function hideMsg():void{
msg.height=0;
msg.width=0;
}
private function showMsg():void{
msg.height=msgHeight;
msg.width=msgWidth;
}
]]>
</mx:Script>
- linha 11: o método init é executado no início da aplicação porque foi escrito:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
creationComplete="init()">
- linhas 13-14: armazenam-se a altura e a largura da área de mensagem. Utilizam-se dois métodos, hideMsg (linhas 48-51) e showMsg (linhas 53-56), para, respectivamente, ocultar/exibir a área de mensagem, dependendo se houve erro ou não. O método hideMsg oculta a área de mensagem definindo sua altura e largura como 0. O método showMsg exibe a área de mensagem, restaurando sua altura e largura armazenadas no método init.
- linha 16: a área de mensagem é ocultada. Inicialmente, não há erro.
- linha 18: o método GetAllIdentitesEmploye (linha 6 do serviço web) do serviço web pam (linha 1 do serviço web) é chamado. A chamada é assíncrona. A linha 7 do serviço web indica que o método loadEmployesCompleted será executado se essa chamada assíncrona for bem-sucedida. A linha 8 do serviço web indica que o método loadEmployesFault será executado se essa chamada assíncrona falhar.
- linha 27: o método loadEmployesCompleted, que é executado se a chamada ao serviço web da linha 18 for bem-sucedida.
- linha 29: sabemos que o serviço web retorna uma resposta XML. É recomendável voltar a ela para entender o código ActionScript:
![]() |
- em [1], página do serviço web [Service.asmx]
- em [2], o link para a página de teste do método [GetAllIdentitesEmployes]
- em [3], o teste foi realizado. Não é esperado nenhum parâmetro.
- em [4]: a resposta XML contém uma tabela de funcionários. Para cada um deles, há cinco informações encapsuladas nas tags <Id>, <Version>, <SS>, <Nom> e <Prenom>. Se a resposta XML for inserida em uma tabela employes do tipo ArrayCollection:
- employes.getItemAt(i): é o elemento nº i da tabela
- employes.getItemAt(i).SS: é o número de previdência social desse funcionário.
- employes.getItemAt(i).Nome: é o nome desse funcionário
- ...
Voltemos ao código ActionScript:
- linha 29: event.result representa a resposta XML do serviço web. O método GetAllIdentitesEmployes retorna uma matriz de funcionários. event.result representa essa matriz de funcionários. Ela é armazenada em uma variável do tipo ArrayCollection, um tipo que representa, de maneira geral, uma coleção de objetos. Essa variável, denominada employes, é declarada na linha 9. Vale lembrar que essa variável é a fonte de dados do menu suspenso de funcionários:
<mx:ComboBox id="cmbEmployes" dataProvider="{employes}" labelFunction="displayEmploye"/>
Para cada funcionário de sua fonte de dados, a lista suspensa chamará o método displayEmploye (atributo labelFunction) para exibir o funcionário. Nas linhas 32 a 34, vemos que esse método exibe o nome e o sobrenome do funcionário.
- linha 37: o método loadEmployesFault, que é executado caso a chamada ao serviço web da linha 18 falhe. event.fault.message é a mensagem de erro retornada pelo serviço web.
- linha 39: essa mensagem de erro é inserida no campo de mensagem
- linha 41: a área de mensagem é exibida.
Quando o aplicativo foi compilado, seu código executável fica na pasta [bin-debug] do projeto Flex:
![]() |
Acima,
- o arquivo [main.html] representa o arquivo HTML, que será solicitado pelo navegador ao servidor web para obter o cliente Flex
- o arquivo [main.swf] é o binário do cliente Flex que será encapsulado na página HTML enviada ao navegador e, em seguida, executado pelo plug-in Flash Player deste.
Estamos prontos para executar o cliente Flex. Antes disso, precisamos configurar o ambiente de execução necessário para ele. Voltemos à arquitetura cliente/servidor testada:
![]() |
Lado do servidor:
- inicie o serviço web ASP.NET [S]
No lado do cliente:
- inicie o servidor Apache, ao qual será solicitada a aplicação Flex.
Aqui, utilizamos a ferramenta Wamp. Com essa ferramenta, podemos associar um alias à pasta [bin-debug] do projeto Flex.
![]() |
- o ícone do Wamp fica na parte inferior da tela [1]
- clicando com o botão esquerdo do mouse no ícone Wamp, selecione a opção Apache [2] / Alias Directories [3, 4]
- selecione a opção [5]: Adicionar um alias
![]() |
- em [6], atribua um alias (qualquer nome) ao aplicativo web que será executado
- em [7], indique a raiz do aplicativo web que terá esse alias: trata-se da pasta [bin-debug] do projeto Flex que acabamos de criar.
Vamos relembrar a estrutura da pasta [bin-debug] do projeto Flex:
![]() |
O arquivo [main.html] é o arquivo HTML do aplicativo Flex. Graças ao alias que acabamos de criar na pasta [bin-debug], esse arquivo será acessado por meio do URL e do [http://localhost/pam-v10-flex-client-webservice/main.html]. Abrimos esse arquivo em um navegador que possua o plugin Flash Player versão 9 ou superior:
![]() |
- no [1], o URL do aplicativo Flex
- em [2], a lista suspensa de funcionários quando tudo está funcionando corretamente
- em [3], o resultado obtido quando o serviço web está desativado
Talvez você tenha curiosidade em visualizar o código-fonte da página HTML recebida:
- O corpo da página começa na linha 25. Ele não contém o HTML clássico, mas um objeto (linha 28) do tipo “application/x-shockwave-flash” (linha 41). É o arquivo [main.swf] (linha 31) que pode ser visto na pasta [bin-debug] do projeto Flex. Trata-se de um arquivo de tamanho considerável: cerca de 600 K para este exemplo simples.
14.4. A visualização nº 2
Vamos adicionar um novo contêiner do tipo VBox à vista atual:
![]() |
![]() |
- em [4,5], definimos [main2.mxml] como o novo aplicativo padrão. É ele que será compilado a partir de agora.
- Em [6], o aplicativo padrão é indicado por um ponto azul.
O contêiner [1] exibirá as informações relativas ao funcionário selecionado no menu suspenso [2]. Duplicamos [main.xml] em [main2.xml] e [3] para construir a nova visualização. A partir de agora, trabalharemos com [main2.xml].
![]() |
A alteração feita no projeto anterior é a adição do contêiner da linha 26 acima, que contém o código MXML do contêiner [1] da visualização. Atribuímos a ele o identificador employe para que possamos manipulá-lo por meio de código. De fato, esse contêiner deverá poder ser ocultado ou exibido pela mesma técnica utilizada anteriormente para a área de mensagem.
Voltemos ao visual da visualização:
![]() |
Identifiquemos os diferentes contêineres das novas informações exibidas:
- V1: contêiner vertical que contém todos os componentes: o rótulo Employé, [1] e os contêineres horizontais [H1] e [H2]
- H1: contêiner horizontal para as informações Nom, Prénom, Adresse
- V2: contêiner vertical para o texto Nom e a exibição do nome do funcionário.
- H2: contêiner horizontal para as informações Ville, CEP, Indice
O código completo do contêiner “employe” é o seguinte:
<mx:VBox id="employe" width="100%">
<mx:Label text="Employé" fontSize="20" color="#09F3EB"/>
<mx:HBox>
<mx:VBox >
<mx:Label text="Nom"/>
<mx:VBox backgroundColor="#EECA05">
<mx:Text id="lblNom" minWidth="100" minHeight="20" fontFamily="Verdana" textAlign="center"/>
</mx:VBox>
</mx:VBox>
<mx:VBox >
<mx:Label text="Prénom"/>
<mx:VBox backgroundColor="#EECA05">
<mx:Text id="lblPreNom" minWidth="100" minHeight="20" fontFamily="Verdana" textAlign="center"/>
</mx:VBox>
</mx:VBox>
<mx:VBox >
<mx:Label text="Adresse"/>
<mx:VBox backgroundColor="#EECA05">
<mx:Text id="lblAdresse" minWidth="250" minHeight="20" fontFamily="Verdana" textAlign="center"/>
</mx:VBox>
</mx:VBox>
</mx:HBox>
<mx:HBox>
<mx:VBox >
<mx:Label text="Ville"/>
<mx:VBox backgroundColor="#EECA05">
<mx:Text id="lblVille" minWidth="100" minHeight="20" fontFamily="Verdana" textAlign="center"/>
</mx:VBox>
</mx:VBox>
<mx:VBox >
<mx:Label text="Code Postal"/>
<mx:VBox backgroundColor="#EECA05">
<mx:Text id="lblCodePostal" minWidth="70" minHeight="20" fontFamily="Verdana" textAlign="center"/>
</mx:VBox>
</mx:VBox>
<mx:VBox >
<mx:Label text="Indice"/>
<mx:VBox backgroundColor="#EECA05">
<mx:Text id="lblIndice" minWidth="20" minHeight="20" fontFamily="Verdana" textAlign="center"/>
</mx:VBox>
</mx:VBox>
</mx:HBox>
</mx:VBox>
O código é autoexplicativo. Vamos explicar, por exemplo, o contêiner vertical que exibe o nome do funcionário:
- linhas 4-9: o contêiner vertical
- linha 5: a legenda Nom
- linhas 6-8: um contêiner vertical que exibirá o nome do funcionário (linha 7). Queremos atribuir uma cor de fundo diferente aos campos que exibem informações sobre o funcionário. O componente Text não oferece essa possibilidade (ou talvez eu não tenha procurado direito). É possível definir a cor de fundo de um contêiner. É por isso que ele foi utilizado aqui.
- linha 7: o componente Text, que exibirá o nome do funcionário. Definimos para ele uma altura e uma largura mínimas.
Vamos usar o contêiner “employe” para exibir as informações do funcionário que o usuário selecionar na lista suspensa de funcionários, independentemente do botão [Salaire], cuja função será, posteriormente, calcular o salário assim que todas as informações necessárias tiverem sido inseridas.
Para gerenciar a mudança de seleção na lista suspensa “employes”, seu código MXML é alterado da seguinte forma:
<mx:ComboBox id="cmbEmployes" dataProvider="{employes}" labelFunction="displayEmploye" change="displayInfosEmploye();"/>
O evento “change” é disparado pela lista suspensa quando o usuário altera sua seleção. O gerenciador desse evento será o método displayInfosEmploye.
Vale lembrar os métodos expostos pelo serviço web remoto:
// lista de todas as identidades dos funcionários
public Employe[] GetAllIdentitesEmployes();
// ------- cálculo do salário
public FeuilleSalaire GetSalaire(string ss, double heuresTravaillees, int joursTravailles);
Queremos aqui exibir as informações (nome, sobrenome, etc.) do funcionário selecionado na lista suspensa. O serviço web não expõe nenhum método para obtê-las. No entanto, podemos usar o método GetSalaire, passando o número SS do funcionário selecionado e 0 para as horas e dias trabalhados. Será realizado um cálculo salarial desnecessário, mas o método GetSalaire nos retornará um objeto do tipo FeuilleSalaire, no qual encontraremos as informações de que precisamos.
A declaração atual do serviço web é modificada para incluir a definição do método GetSalaire:
<mx:WebService id="pam"
wsdl="http://localhost:1077/Service1.asmx?WSDL"
fault="wsFault(event);"
showBusyCursor="true">
<mx:operation
name="GetAllIdentitesEmployes"
result="loadEmployesCompleted(event)"
fault="loadEmployesFault(event);">
<mx:request/>
</mx:operation>
<mx:operation name="GetSalaire"
result="getSalaireCompleted(event)"
fault="getSalaireFault(event);">
<mx:request>
<ss>{employes.getItemAt(cmbEmployes.selectedIndex).SS}</ss>
<heuresTravaillees>{heuresTravaillees}</heuresTravaillees>
<joursTravailles>{joursDeTravail}</joursTravailles>
</mx:request>
</mx:operation>
</mx:WebService>
- linhas 11-19: a definição do método GetSalaire do serviço web
- linha 12: define o método a ser executado quando a chamada ao método GetSalaire for bem-sucedida
- linha 13: define o método a ser executado quando a chamada ao método GetSalaire falhar
- linhas 14-18: o método GetSalaire espera três parâmetros. Eles são definidos dentro de uma tag <mx:request> na forma <param1>valor1</param1>. O identificador param1 não pode ser qualquer um. É necessário utilizar os nomes esperados pelo serviço web:
![]() |
- em [1], a página do serviço web [http://localhost:1077/Service1.asmx]
- em [2], o link para a página de teste do método [GetSalaire]
- em [3], os parâmetros esperados pelo método. São esses nomes que devem ser usados como tags filhas da tag <mx:request>.
Voltemos à declaração do serviço web:
<mx:operation name="GetSalaire"
result="getSalaireCompleted(event)"
fault="getSalaireFault(event);">
<mx:request>
<ss>{employes.getItemAt(cmbEmployes.selectedIndex).SS}</ss>
<heuresTravaillees>{heuresTravaillees}</heuresTravaillees>
<joursTravailles>{joursDeTravail}</joursTravailles>
</mx:request>
</mx:operation>
- linha 5: o parâmetro ss. Lembramos que, ao iniciar o aplicativo Flex, a tabela com todos os funcionários foi armazenada em uma variável `empregados` do tipo ArrayCollection.
- employes.getItemAt(i): é o funcionário nº i da tabela
- employes.getItemAt(i).SS: é o número de previdência social desse funcionário.
- cmbEmployes.selectedIndex: é o número do elemento selecionado na lista suspensa de funcionários cmbemployes.
No exemplo acima, como sabemos que SS é o número de previdência social de um funcionário? Para isso, é preciso voltar à resposta enviada pelo método GetAllIdentitesEmployes:
![]() |
- em [1], página do serviço web [Service.asmx]
- em [2], o link para a página de teste do método [GetAllIdentitesEmployes]
- em [3], o teste está concluído. Não é esperado nenhum parâmetro.
- em [4]: a resposta XML contém uma tabela de funcionários. É essa tabela que foi armazenada na variável employes. Vemos em [5] que SS é, de fato, a tag utilizada para conter o número do seguro social.
Concluamos a análise do serviço web:
<mx:operation name="GetSalaire"
result="getSalaireCompleted(event)"
fault="getSalaireFault(event);">
<mx:request>
<ss>{employes.getItemAt(cmbEmployes.selectedIndex).SS}</ss>
<heuresTravaillees>{heuresTravaillees}</heuresTravaillees>
<joursTravailles>{joursDeTravail}</joursTravailles>
</mx:request>
</mx:operation>
- linha 6: o número de horas trabalhadas será fornecido pela variável heuresTravaillees
- linha 6: o número de dias trabalhados será fornecido por uma variável joursDeTravail
Essas variáveis devem ser declaradas na tag <mx:Script> com o atributo [Bindable], que permite que sejam referenciadas por componentes MXML (linhas 7 a 10 abaixo).
<mx:Script>
<![CDATA[
...
// dados
[Bindable]
private var employes : ArrayCollection;
[Bindable]
private var heuresTravaillees:Number;
[Bindable]
private var joursDeTravail:int;
...
</mx:Script>
O código de gerenciamento de eventos da visualização é alterado da seguinte forma:
<mx:Script>
<![CDATA[
import mx.rpc.events.FaultEvent;
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
// dados
[Bindable]
private var employes : ArrayCollection;
[Bindable]
private var heuresTravaillees:Number;
[Bindable]
private var joursDeTravail:int;
private function init():void{
// registra-se a altura e a largura de # blocos
employeHeight=employe.height;
employeWidth=employe.width;
// ocultamos alguns elementos
hideEmploye();
...
}
private function displayInfosEmploye():void{
// formulário
hideEmploye();
// calcula-se um salário fictício
heuresTravaillees=0;
joursDeTravail=0;
pam.GetSalaire.send();
}
private function getSalaireCompleted(event:ResultEvent):void{
...
}
private function getSalaireFault(event:FaultEvent):void{
...
}
// visualizações parciais -------------------------------------------------
private var employeHeight:int;
private var employeWidth:int;
private function hideEmploye():void{
employe.height=0;
employe.width=0;
}
private function showEmploye():void{
employe.height=employeHeight;
employe.width=employeWidth;
}
]]>
</mx:Script>
- linha 15: o método init, executado ao iniciar o aplicativo Flex, armazena a altura e a largura do contêiner vertical employe, a fim de poder restaurá-lo (linhas 50-53) após ocultá-lo (linhas 45-48).
- linha 24: o método displayInfosEmploye é executado quando o usuário altera sua seleção na lista suspensa de funcionários.
- linha 26: o contêiner employe é ocultado caso estivesse visível
- linha 30: o método GetSalaire do serviço web é chamado de forma assíncrona. Sabe-se que ele espera três parâmetros:
<ss>{employes.getItemAt(cmbEmployes.selectedIndex).SS}</ss>
<heuresTravaillees>{heuresTravaillees}</heuresTravaillees>
<joursTravailles>{joursDeTravail}</joursTravailles>
- linha 1: o parâmetro ss será o número SS do funcionário selecionado na lista suspensa de funcionários
- linha 2: o método displayInfosEmploye atribui o valor 0 à variável heuresTravaillees (linha 28)
- linha 3: o método displayInfosEmploye atribui o valor 0 à variável joursDeTravail (linha 29)
O método GetSalaireCompleted é executado se o método GetSalaire do serviço web for concluído com sucesso:
private function getSalaireCompleted(event:ResultEvent):void{
// ocultamos a mensagem de erro
hideMsg();
// recebe-se um holerite
var feuilleSalaire:Object=event.result;
// exibição
lblNom.text=feuilleSalaire.Employe.Nom;
lblPreNom.text=feuilleSalaire.Employe.Prenom;
lblAdresse.text=feuilleSalaire.Employe.Adresse;
lblVille.text=feuilleSalaire.Employe.Ville;
lblCodePostal.text=feuilleSalaire.Employe.CodePostal;
lblIndice.text=feuilleSalaire.Employe.Indice;
showEmploye();
}
- linha 3: oculta-se a área de mensagem, caso ela venha a ser exibida.
- linha 5: recupera-se a folha de pagamento retornada pelo método GetSalaire
Para saber exatamente o que o método GetSalaire retorna, voltamos à página do serviço web:
![]() |
- em [1], a página do serviço web [Service.asmx]
- para [2], o link que leva à página de teste do método [GetSalaire]
- em [3], são fornecidos parâmetros
- em [4], o resultado XML obtido.
Voltemos ao método getSalaireCompleted:
private function getSalaireCompleted(event:ResultEvent):void{
// oculta-se a mensagem de erro
hideMsg();
// recebe-se uma folha de pagamento
var feuilleSalaire:Object=event.result;
// exibição
lblNom.text=feuilleSalaire.Employe.Nom;
lblPreNom.text=feuilleSalaire.Employe.Prenom;
lblAdresse.text=feuilleSalaire.Employe.Adresse;
lblVille.text=feuilleSalaire.Employe.Ville;
lblCodePostal.text=feuilleSalaire.Employe.CodePostal;
lblIndice.text=feuilleSalaire.Employe.Indemnites.Indice;
showEmploye();
}
- linha 5: feuilleSalaire=event.result representa o fluxo XML [4] retornado pelo método GetSalaire. De acordo com esse fluxo, observa-se que:
- feuilleSalaire.Employe é o fluxo XML de um funcionário
- feuilleSalaire.Employe.Nom é o nome desse funcionário
- ...
- linhas 7-12: o fluxo XML feuilleSalaire é utilizado para preencher os diversos campos do contêiner “empregado”.
- linha 13: o contêiner “empregado” é exibido.
O método getSalaireFault é executado se o método GetSalaire do serviço web falhar:
private function getSalaireFault(event:FaultEvent):void{
// exibição da mensagem de erro
msg.text=event.fault.message;
// formulário
showMsg();
}
- linha 3: a mensagem de erro event.fault.message é inserida no campo de mensagem
- linha 5: o campo de mensagem é exibido
Aqui terminam as modificações necessárias para esta nova versão. Ao salvá-la, e se ela estiver sintaticamente correta, a versão executável é gerada na pasta [bin-debug] do projeto:
![]() |
Acima, [main2.html] é a página HTML que incorpora o binário do aplicativo Flex [main2.swf], que será executado pelo Flash Player.
Podemos testar essa nova versão:
- o serviço web ASP.NET deve estar em execução
- o servidor Apache deve ser iniciado para o cliente Flex
Supondo que o alias [pam-v10-flex-client-webservice] usado na versão anterior ainda exista, solicitamos ao servidor Apache o URL e o [http://localhost/pam-v10-flex-client-webservice/main2.html] em um navegador:
![]() |
![]() |
- em [1], o URL solicitado
- em [2], a lista suspensa de funcionários
- em [3], altera-se a seleção no menu suspenso para acionar o evento change
- em [4], o resultado obtido: o perfil de Justine Laverti.
14.5. A visualização nº 3
A visualização nº 3 realiza a verificação de validade do formulário. Aqui, apenas o campo de preenchimento “txtHeuresTravaillees” é verificado. Enquanto o formulário estiver incorreto, o botão “btnSalaire” permanecerá desativado.
Para adicionar essa funcionalidade, duplicamos [main2.mxml] em [main3.mxml]:
![]() |
A partir de agora, trabalharemos com o [main3.mxml], que será definido como o aplicativo padrão (consulte este conceito no parágrafo 14.4). Primeiramente, adicionamos um atributo ao componente “txtHeuresTravaillees”:
<mx:TextInput id="txtHeuresTravaillees" change="validateForm(event)"/>
Sempre que o conteúdo do campo de entrada “txtHeuresTravaillees” for alterado, o método validateForm será chamado. Trata-se de um método local escrito pelo desenvolvedor. Nele, poderíamos verificar se o conteúdo do campo de entrada “txtHeuresTravaillees” é realmente um número inteiro positivo. Vamos proceder de outra forma, utilizando um componente de validação:
<mx:NumberValidator id="heuresTravailleesValidator" source="{txtHeuresTravaillees}" property="text"
precision="2" allowNegative="false"
invalidCharError="Caractères invalides"
precisionError="Deux chiffres au plus après la virgule"
negativeError="Le nombre d'heures doit être positif ou nul"
invalidFormatCharsError="Format invalide"
required="true"
requiredFieldError="Donnée requise"/>
- linha 1: o componente <mx:NumberValidator> permite verificar se outro componente contém um número inteiro ou real.
- linha 1: o atributo id atribui um identificador ao componente.
- linha 1: source é o ID do componente verificado pelo componente NumberValidator. Aqui, é o campo de entrada “txtHeuresTravaillees” que está sendo verificado.
- linha 1: property é o nome da propriedade do componente source que contém o valor a ser verificado. No final, é o valor source.property que é verificado, neste caso txtHeuresTravaillees.text.
- linha 2: precision define o número máximo de casas decimais permitidas. precision=0 serve para verificar se o número inserido é inteiro.
- linha 2: allowNegative indica se números negativos são permitidos ou não
- linha 7: required indica se a entrada é obrigatória ou não.
Quando uma condição de validação não é verificada, uma mensagem de erro é exibida em um balão próximo ao componente com erro. Por padrão, essas mensagens estão em inglês. É possível definir essas mensagens por conta própria:
- (continuação)
- invalidCharError: a mensagem de erro quando o texto contém um caractere que não pode ser encontrado em um número
- precisionError: a mensagem de erro quando o número de casas decimais está incorreto em relação ao atributo precision
- negativeError: a mensagem de erro quando o número é negativo, embora o atributo allowNegative esteja definido como “false”
- requiredFieldError: a mensagem de erro quando não houve entrada de dados, embora o atributo requiredField esteja definido como "true"
- invalidFormatCharsError: a mensagem de erro quando o texto contém caracteres ou um formato inválido?
Voltemos ao componente “txtHeuresTravaillees”:
<mx:TextInput id="txtHeuresTravaillees" change="validateForm(event)"/>
O método validateForm poderia ser o seguinte na tag <mx:Script>:
private function validateForm(event:Event):void
{
// valida-se as horas trabalhadas
var evt:ValidationResultEvent = heuresTravailleesValidator.validate();
// validação bem-sucedida?
btnSalaire.enabled=evt.type==ValidationResultEvent.VALID;
}
- linha 4: o validador “heuresTravailleesValidator” é executado. Ele retorna um resultado do tipo ValidationResultEvent.
- linha 6: evt.type é do tipo String e indica o tipo do evento. evt.type tem dois valores possíveis para o tipo ValidationResultEvent: “invalid” ou “valid”, representados pelas constantes ValidationResultEvent.INVALID e ValidationResultEvent.VALID. Se, na linha 4, a validação tiver sido bem-sucedida, evt.type deve ter como valor ValidationResultEvent.VALID. Nesse caso, o botão btnSalaire fica ativado; caso contrário, fica desativado.
Isso é suficiente para testar a validade das horas trabalhadas.
![]() |
Acima, a compilação do projeto gerou os arquivos [main3.html] e [main3.swf]. Abrimos o URL e o [http://localhost/pam-v10-flex-client-webservice/main3.html] em um navegador e verificamos diversos casos de erro:
![]() |
![]() |
- um campo com erro apresenta uma borda vermelha ([1, 2, 3]), enquanto um campo correto apresenta uma borda azul ([4]).
- Em [4], observe-se que o botão [Salaire] está ativo porque o número de horas trabalhadas está correto.
14.6. A visualização nº 4
A visualização n.º 4 conclui o formulário de cálculo do salário. Para isso, duplicamos [main3.xml] em [main4.xml] e passamos a trabalhar com main4, que definimos como aplicação padrão (ver parágrafo 14.4).
![]() |
As alterações feitas em [main4.xml] e [1] são as seguintes:
- um novo contêiner vertical foi adicionado à visualização [2] para exibir os elementos do salário do funcionário
- foi adicionado um componente que permite formatar valores monetários no [3]
- a exibição dos elementos da remuneração é controlada pelo gerenciador associado ao evento “clique” do botão “btnSalaire”.
A visualização é alterada da seguinte forma:
![]() |
O novo contêiner segue o mesmo princípio do anterior. Trata-se de um contêiner vertical VBox [V1] que contém quatro contêineres horizontais HBox [Hi]. Os contêineres horizontais H1 a H3 são formados por contêineres verticais que contêm dois rótulos, sendo que o segundo está, por sua vez, dentro de um contêiner vertical para ter uma cor de fundo.
Questão 1: escreva o contêiner do salário. Ele será chamado, a seguir, de complements.
Questão 2: escreva os métodos que permitem ocultar/exibir o contêiner complements. Inspire-se no que foi feito anteriormente para o contêiner employe.
Associamos um manipulador ao evento “click” do botão “btnSalaire”:
<mx:Button id="btnSalaire" label="Salaire" click="calculerSalaire()"/>
O método calculerSalaire é o seguinte:
private function calculerSalaire():void{
// preparação do formulário
affichageSalaire=true;
msg.text="";
// parâmetros do cálculo do salário
heuresTravaillees=Number(txtHeuresTravaillees.text);
joursDeTravail=int(joursTravailles.value);
// o salário é solicitado ao serviço web
pam.GetSalaire.send();
}
- linha 3: o booleano affichageSalaire serve para indicar se o contêiner complements, que exibe os elementos do salário, deve ou não ser exibido. O método getSalaireCompleted é executado em dois eventos:
- a mudança de funcionário na lista suspensa de funcionários para exibir suas informações sem o salário. Nesse caso, definirá-se affichageSalaire=false.
- o cálculo do salário
- linha 6: o texto do campo de entrada txtHeuresTravaillees é convertido em número real.
- linha 7: o valor do incrementador joursTravailles é convertido em número inteiro.
- linha 9: chamada do método remoto GetSalaire. Vale lembrar que esse método espera três parâmetros, entre os quais os parâmetros heuresTravaillees e joursDeTravail, inicializados nas linhas 6 e 7. Vale lembrar também que, se a chamada assíncrona do método GetSalaire:
- for bem-sucedida, o método getSalaireCompleted será chamado
- falhar, o método getSalaireFault será chamado
Pergunta 3: complementar o método atual getSalaireCompleted para que ele exiba o salário do funcionário caso o botão btnSalaire tenha sido clicado.
Atualmente, a exibição dos itens do salário é feita sem o símbolo do euro. É possível incluir esse símbolo no código ou utilizar um formatador. É isso que está sendo proposto agora. O formatador será o seguinte:
<mx:CurrencyFormatter id="eurosFormatter" precision="2"
currencySymbol="€" useNegativeSign="true"
alignSymbol="right"/>
- linha 1: id é o identificador do formador, precision o número de casas decimais a serem mantidas.
- linha 2: currencySymbol é o símbolo monetário a ser utilizado. useNegativeSign indica se deve ou não ser utilizado o sinal - para valores negativos.
- linha 3: alignSymbol indica onde colocar o símbolo monetário em relação ao número.
Este formador é utilizado no código do script da seguinte maneira:
- eurosFormatter é o ID do formatador a ser utilizado
- format é o método a ser chamado para formatar um número. Ele retorna uma sequência de caracteres.
- feuilleSalaire.Indemnites.BaseHeure é, neste caso, o número a ser formatado.
- lblSH é o nome de um componente do tipo Text.
Questão 4: modifique o método getSalaireCompleted para que ele utilize o formatador monetário.





























