14. Додаток [SimuPaie] — версія 10 — Flex-клієнт веб-сервісу ASP.NET
Тепер ми презентуємо клієнт Flex для веб-сервісу ASP.NET версії 5. Використовується Flex Builder 3 (IDE). Демо-версію цього продукту можна завантажити за посиланням URL [https://www.adobe.com/cfusion/tdrc/index.cfm?loc=fr_fr&product=flex]. Flex Builder 3 — це IDE Eclipse. Крім того, для запуску клієнта Flex ми використовуємо веб-сервер Apache з інструменту Wamp [http://www.wampserver.com/]. Підійде будь-який сервер Apache. Браузер, який відображає клієнт Flex, повинен мати плагін Flash Player версії не нижче 9.
Особливістю додатків Flex є те, що вони виконуються всередині плагіна Flash Player браузера. У цьому вони схожі на додатки Ajax, які вбудовують у сторінки, що надсилаються до браузера, скрипти JavaScript, які потім виконуються безпосередньо в браузері. Додаток Flex не є веб-додатком у звичному розумінні цього слова: це клієнтський додаток, що використовує сервіси, які надаються веб-серверами. У цьому він аналогічний настільному додатку, який також був би клієнтом цих самих сервісів. Однак він відрізняється в одному: спочатку його завантажують із веб-сервера у браузері, що має плагін Flash Player, здатний його виконати.
Як і настільний додаток, додаток Flex складається переважно з двох елементів:
- презентаційної частини: це вікна, що відображаються у браузері. Ці вікна мають таку ж функціональність, як і вікна настільних програм. Вікно описується за допомогою мови тегів, що називається MXML.
- кодова частина, яка в основному обробляє події, спричинені діями користувача на екрані. Цей код також можна писати на MXML або на об’єктно-орієнтованій мові, що називається ActionScript. Слід розрізняти два типи подій:
- подія, яка вимагає обміну даними з веб-сервером: заповнення списку даними, наданими веб-додатком, надсилання даних з форми на сервер тощо. Flex надає низку методів для взаємодії з сервером, що є прозорою для розробника. Ці методи за замовчуванням є асинхронними: користувач може продовжувати взаємодіяти з представленням під час запиту до сервера.
- подія, яка змінює відображуваний вигляд без обміну даними з сервером, наприклад, перетягування елемента з дерева для розміщення його у списку. Цей тип події повністю обробляється локально в браузері.
Додаток Flex зазвичай виконується таким чином:
![]() |
- у [1] запитується сторінка HTML
- у [2], її надсилають. Вона містить бінарний файл SWF (ShockWave Flash), що містить весь додаток Flex: усі представлення та код обробки подій для них. Цей файл буде виконано плагіном Flash Player браузера.
![]() |
- Виконання клієнта Flex відбувається локально в браузері, за винятком випадків, коли йому потрібні зовнішні дані. У такому разі він запитує їх у сервера [3]. Він отримує їх у форматі [4] у різних форматах: XML або бінарному. Додаток, до якого звертаються на веб-сервері, може бути написаний будь-якою мовою. Важливим є лише формат відповіді.
Ми описали архітектуру виконання додатка Flex, щоб читач міг зрозуміти різницю між нею та архітектурою класичного веб-додатка, де сторінки не містять коду (JavaScript, Flex, Silverlight тощо), який би виконував браузер. У останньому випадку браузер є пасивним: він просто відображає сторінки HTML, створені на веб-сервері, який їх надсилає.
14.1. Архітектура клієнт-серверного додатка
Впроваджена архітектура «клієнт/сервер» аналогічна архітектурі версій 6 та 8:
![]() |
У [1] веб-шар ASP.NET замінено на веб-шар Flex, написаний на MXML та ActionScript. Клієнт [C] буде згенерований за допомогою Flex Builder IDE. Слід нагадати, що ця архітектура включає два веб-сервери, які не зображені:
- веб-сервер ASP.NET, який виконує веб-сервіс [S]
- веб-сервер APACHE, на якому виконується веб-клієнт [1]
14.2. Проєкт клієнта на Flex 3
Ми створюємо клієнт Flex за допомогою Flex Builder 3:
![]() |
- у Flex Builder 3 створюємо новий проєкт у [1]
- даємо йому ім’я [2] та вказуємо [3], у якій папці його створити
![]() |
- у [4] надаємо ім’я головній програмі (тієї, що буде виконуватися)
- у полі [5] — проект після генерації
- у [6] — головний файл програми MXML
- файл MXML містить представлення та код обробки його подій. Вкладка [Source] [7] надає доступ до файлу MXML. У ньому містяться теги <mx>, що описують вікно, а також код ActionScript.
- Вигляд можна побудувати графічно за допомогою вкладок [Design] та [8]. Теги MXML, що описують вигляд, тоді автоматично генеруються у вкладці [Source]. Діє й зворотне: теги MXML, додані безпосередньо у вкладці [Source], відображаються графічно у вкладці [Design].
14.3. Вигляд № 1
Ми поступово створимо веб-інтерфейс, аналогічний інтерфейсу версії 1 (див. параграф 4). Спочатку створимо такий інтерфейс:
![]() |
- у [1] — екран, що відображається, коли вдалося встановити з’єднання з веб-сервісом. У цьому випадку комбінований список співробітників заповнюється.
- у [2] — вигляд екрана, коли підключення до веб-сервісу не вдалося. У цьому випадку відображається повідомлення про помилку.
Основний файл клієнта [main.xml] має такий вигляд:
<?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[
...
// дані
[Bindable]
private var employes : ArrayCollection;
private function init():void{
...
}
]]>
</mx:Script>
</mx:Application>
У цьому коді слід розрізняти різні елементи:
- визначення додатка (рядки 2–3)
- опис його інтерфейсу (рядки 4–25)
- обробники подій на мові ActionScript у тезі <mx:Script> (рядки 31–42).
- визначення віддаленого веб-сервісу (рядки 27–29)
Для початку прокоментуємо визначення самого додатка та опис його інтерфейсу:
- рядки 2–3: визначають:
- спосіб розміщення компонентів у контейнері подання. Атрибут layout="vertical" вказує, що компоненти будуть розташовані один під одним.
- метод, який потрібно виконати після створення екземпляра подання, c.a.d. момент, коли всі його компоненти будуть створені. Атрибут creationComplete="init();" вказує, що має бути виконано метод init із рядка 38. creationComplete — це одна з подій, які може генерувати клас Application.
- рядки 4–25 визначають компоненти подання
- рядки 4–25: вертикальний контейнер: компоненти будуть розміщені в ньому один під одним
- рядок 5: визначає текст
- рядки 6–23: горизонтальний контейнер: компоненти будуть розміщені в ньому горизонтально.
- рядки 7–10: вертикальний контейнер, який міститиме текст і випадаючий список
- рядок 8: текст
- рядок 9: випадаючий список, у який буде вставлено список співробітників. Тег dataProvider="{employes}" вказує джерело даних, якими має заповнюватися список. У цьому випадку список буде заповнено об’єктом employes, визначеним у рядку 36. Щоб можна було написати dataProvider="{employes}", поле employes повинно мати атрибут [Bindable] (рядок 35). Цей атрибут дозволяє посилатися на змінну ActionScript поза тегом <mx:Script>. Поле employes має тип ArrayCollection — тип ActionScript, що дозволяє зберігати списки об’єктів, у даному випадку список об’єктів типу Employe.
- рядки 11–14: вертикальний контейнер, який міститиме текст та поле введення
- рядок 12: текст
- рядок 13: поле введення відпрацьованих годин.
- рядки 15–18: вертикальний контейнер, який міститиме текст та лічильник
- рядок 16: текст
- рядок 17: лічильник, що дозволить вводити кількість відпрацьованих днів.
- рядки 19–22: вертикальний контейнер, що міститиме текст та кнопку, яка запускатиме розрахунок заробітної плати особи, обраної у комбінованому списку.
- рядок 20: текст
- рядок 21: кнопка.
- рядок 23: кінець горизонтального контейнера, що починається з рядка 6
- рядок 24: текстове поле у компоненті типу TextArea. У ньому будуть відображатися повідомлення про помилки.
- рядок 25: кінець вертикального контейнера, розпочатого в рядку 4
Рядки 4–25 формують таке відображення у вкладці [Design]:
![]() |
- [1]: було згенеровано компонентом Label із рядка 5
- [2]: було згенеровано компонентом ComboBox у рядку 9
- [3]: було згенеровано компонентом TextInput у рядку 13
- [4]: було згенеровано компонентом NumericStepper з рядка 17
- [5]: було згенеровано компонентом Button у рядку 21
- [6]: було згенеровано компонентом TextArea у рядку 24
Тепер розглянемо оголошення віддаленого веб-сервісу:
<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>
- рядок 1: веб-сервіс має ідентифікатор pam (атрибут id)
- рядок 2: URI файлу WSDL веб-сервісу (див. параграф 9.2)
- рядок 3: метод, який слід виконати у разі помилки під час обміну даними з веб-сервісом: метод wsFault.
- рядок 4: запит на відображення індикатора, щоб показати користувачеві, що триває обмін даними з веб-сервісом.
- рядки 5–10: одна з операцій, що надаються віддаленим веб-сервісом. У даному випадку — метод GetAllIdentitesEmployes.
- рядок 7: метод, який слід виконати, коли виклик цього методу завершиться нормально, c.a.d. коли веб-сервіс успішно поверне список співробітників
- рядок 8: метод, який слід виконати, коли виклик цього методу завершується з помилкою.
- рядок 9: параметри операції GetAllIdentitesEmployes. Відомо, що цей метод не очікує параметрів. Тому тег <mx:request> залишаємо порожнім.
Тепер розглянемо код ActionScript, пов’язаний із веб-сервісом:
<mx:Script>
<![CDATA[
import mx.rpc.events.FaultEvent;
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
// дані
[Bindable]
private var employes : ArrayCollection;
private function init():void{
// записуються координати області повідомлення
msgHeight=msg.height;
msgWidth=msg.width;
// приховування області повідомлення
hideMsg();
// запит до віддаленого веб-сервісу для отримання спрощеного списку співробітників
pam.GetAllIdentitesEmployes.send();
}
private function wsFault(event:Event):void{
// повідомлення про помилку
msg.text="Service distant indisponible";
showMsg();
}
private function loadEmployesCompleted(event:ResultEvent):void{
// заповнення комбінованого списку співробітників
employes=event.result as ArrayCollection;
}
private function displayEmploye(employe:Object):String{
// ідентифікатор співробітника
return employe.Prenom + " " + employe.Nom;
}
private function loadEmployesFault(event:FaultEvent):void{
// відображення повідомлення про помилку
msg.text=event.fault.message;
// форма
showMsg();
}
// управління блоками
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>
- рядок 11: метод init виконується під час запуску програми, оскільки ми написали:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
creationComplete="init()">
- рядки 13–14: зберігаються висота та ширина області повідомлення. Використовуються два методи: hideMsg (рядки 48–51) та showMsg (рядки 53–56) для приховування та показу області повідомлення відповідно до того, чи сталася помилка. Метод hideMsg приховує область повідомлення, встановлюючи її висоту та ширину на 0. Метод showMsg відображає область повідомлення, відновлюючи її висоту та ширину, збережені в методі init.
- рядок 16: область повідомлення приховується. Спочатку помилки немає.
- рядок 18: викликається метод GetAllIdentitesEmploye (рядок 6 веб-сервісу) веб-сервісу pam (рядок 1 веб-сервісу). Виклик є асинхронним. У рядку 7 веб-сервісу вказано, що метод loadEmployesCompleted буде виконано, якщо цей асинхронний виклик завершиться успішно. У рядку 8 веб-сервісу вказано, що метод loadEmployesFault буде виконано, якщо цей асинхронний виклик завершиться з помилкою.
- рядок 27: метод loadEmployesCompleted, який виконується, якщо виклик веб-сервісу з рядка 18 завершиться успішно.
- рядок 29: відомо, що веб-сервіс повертає відповідь XML. Варто повернутися до неї, щоб зрозуміти код ActionScript:
![]() |
- у [1], сторінка веб-сервісу [Service.asmx]
- в [2] — посилання на сторінку тестування методу [GetAllIdentitesEmployes]
- в [3] — тест виконано. Параметри не очікуються.
- у [4]: відповідь XML містить масив співробітників. Для кожного з них є п’ять елементів інформації, укладених у теги <Id>, <Version>, <SS>, <Nom>, <Prenom>. Якщо відповідь XML поміщається в масив employes типу ArrayCollection:
- employes.getItemAt(i): є елементом № i масиву
- employes.getItemAt(i).SS: — номер соціального страхування цього працівника.
- employes.getItemAt(i).Ім’я: — це ім’я цього працівника
- ...
Повернемося до коду ActionScript:
- рядок 29: event.result представляє відповідь XML від веб-сервісу. Метод GetAllIdentitesEmployes повертає масив співробітників. event.result представляє цей масив співробітників. Вона розміщується у змінній типу ArrayCollection, який загалом представляє колекцію об’єктів. Ця змінна, що має ім’я employes, оголошена у рядку 9. Нагадаємо, що ця змінна є джерелом даних для комбінованого списку співробітників:
<mx:ComboBox id="cmbEmployes" dataProvider="{employes}" labelFunction="displayEmploye"/>
Для кожного співробітника зі свого джерела даних комбінований список викликатиме метод displayEmploye (атрибут labelFunction) для відображення співробітника. У рядках 32–34 ми бачимо, що цей метод відображає прізвище та ім’я співробітника.
- рядок 37: метод loadEmployesFault, який виконується, якщо виклик веб-сервісу з рядка 18 завершується з помилкою. event.fault.message — це повідомлення про помилку, яке повертає веб-сервіс.
- рядок 39: це повідомлення про помилку розміщується в полі повідомлення
- рядок 41: область повідомлення відображається.
Після компіляції додатка його виконуваний код знаходиться у папці [bin-debug] проекту Flex:
![]() |
Вищезазначений
- файл [main.html] відповідає файлу HTML, який браузер буде запитувати у веб-сервера для отримання клієнта Flex
- файл [main.swf] — це бінарний файл клієнта Flex, який буде вбудовано у сторінку HTML, надіслану до браузера, а потім виконано за допомогою плагіна Flash Player цього браузера.
Ми готові запустити клієнт Flex. Але спершу нам потрібно налаштувати необхідне для нього середовище виконання. Повернімося до протестованої архітектури «клієнт/сервер»:
![]() |
На стороні сервера:
- запустити веб-сервіс ASP.NET [S]
На стороні клієнта:
- запустити сервер Apache, до якого буде надходити запит на додаток Flex.
Тут ми використовуємо інструмент Wamp. За допомогою цього інструменту ми можемо прив’язати псевдонім до папки [bin-debug] проекту Flex.
![]() |
- іконка Wamp знаходиться внизу екрану [1]
- клацнувши лівою кнопкою миші на іконці Wamp, виберіть опцію Apache [2] / Alias Directories [3, 4]
- виберіть опцію [5]: «Додати псевдонім»
![]() |
- у [6] присвоїти псевдонім (будь-яке ім’я) веб-додатку, який буде запущено
- у [7] вкажіть кореневу папку веб-додатку, який матиме цей псевдонім: це папка [bin-debug] проекту Flex, який ми щойно створили.
Нагадаємо структуру папки [bin-debug] проекту Flex:
![]() |
Файл [main.html] — це файл HTML веб-додатку Flex. Завдяки псевдоніму, який ми щойно створили для папки [bin-debug], цей файл можна отримати за адресою URL [http://localhost/pam-v10-flex-client-webservice/main.html]. Ми відкриваємо його у браузері з плагіном Flash Player версії 9 або вище:
![]() |
- у [1], URL з додатка Flex
- в [2] — комбінація співробітників, коли все гаразд
- в [3] — результат, отриманий при зупинці веб-сервісу
Можливо, вам буде цікаво переглянути вихідний код отриманої сторінки HTML:
- Основний текст сторінки починається з 25-го рядка. Він містить не класичний HTML, а об’єкт (28-й рядок) типу «application/x-shockwave-flash» (41-й рядок). Це файл [main.swf] (рядок 31), який можна побачити в папці [bin-debug] проекту Flex. Це файл значного розміру: приблизно 600 К для цього простого прикладу.
14.4. Вигляд № 2
Ми додамо новий контейнер типу VBox до поточного виду:
![]() |
![]() |
- у [4,5] ми робимо [main2.mxml] новим додатком за замовчуванням. Саме він відтепер буде компілюватися.
- У [6] додаток за замовчуванням позначено синьою крапкою.
Контейнер [1] відображатиме інформацію про співробітника, вибраного у комбінованому списку [2]. Ми дублюємо [main.xml] у [main2.xml] та [3], щоб створити новий вигляд. Відтепер ми працюватимемо з [main2.xml].
![]() |
Зміною, внесеною до попереднього проєкту, є додавання контейнера з рядка 26 вище, який містить код MXML з контейнера [1] цього виду. Ми присвоюємо йому ідентифікатор employe, щоб мати змогу керувати ним за допомогою коду. Адже цей контейнер має мати можливість приховуватися/відображатися за допомогою тієї ж техніки, що й раніше використовувалася для області повідомлення.
Повернемося до візуального представлення подання:
![]() |
Визначимо різні контейнери нової інформації, що відображається:
- V1: вертикальний контейнер для всіх компонентів: напис Employé, [1] та горизонтальні контейнери [H1] і [H2]
- H1: горизонтальний контейнер для інформації Nom, Prénom, Adresse
- V2: вертикальний контейнер для назви Nom та відображення імені співробітника.
- H2: горизонтальний контейнер для інформації Ville, поштового індексу, Indice
Повний код контейнера «employe» виглядає так:
<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>
Код зрозумілий сам по собі. Просто пояснимо, як працює вертикальний контейнер, що відображає, наприклад, ім’я співробітника:
- рядки 4–9: вертикальний контейнер
- рядок 5: позначення Nom
- рядки 6–8: вертикальний контейнер, який відображатиме ім’я працівника (рядок 7). Ми хочемо надати інший колір фону полям, що відображають інформацію про співробітника. Компонент Text не надає такої можливості (або я неправильно шукав). Можна встановити колір фону контейнера. Саме тому його й було використано тут.
- рядок 7: компонент Text, який відображатиме ім’я співробітника. Ми задаємо йому мінімальну висоту та ширину.
Ми будемо використовувати контейнер «employe» для відображення інформації про співробітника, якого користувач вибирає у комбінованому списку співробітників, незалежно від кнопки [Salaire], роль якої полягатиме в подальшому розрахунку заробітної плати після введення всієї необхідної інформації.
Щоб обробляти зміну вибору у комбінованому списку «employes», його код MXML змінюється наступним чином:
<mx:ComboBox id="cmbEmployes" dataProvider="{employes}" labelFunction="displayEmploye" change="displayInfosEmploye();"/>
Подія «change» надсилається комбінованим списком, коли користувач змінює свій вибір. Обробником цієї події буде метод displayInfosEmploye.
Нагадаємо методи, що надаються віддаленим веб-сервісом:
// перелік усіх ідентифікаційних даних співробітників
public Employe[] GetAllIdentitesEmployes();
// ------- розрахунок заробітної плати
public FeuilleSalaire GetSalaire(string ss, double heuresTravaillees, int joursTravailles);
Тут ми хочемо відобразити інформацію (прізвище, ім’я тощо) про співробітника, вибраного у комбінованому списку. Веб-сервіс не надає методу для отримання цих даних. Проте ми можемо використати метод GetSalaire, передавши номер SS вибраного працівника та значення 0 для відпрацьованих годин і днів. Буде виконано непотрібний розрахунок заробітної плати, але метод GetSalaire поверне нам об’єкт типу FeuilleSalaire, у якому ми знайдемо необхідну інформацію.
Поточна декларація веб-сервісу змінена з метою включення визначення методу 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>
- рядки 11–19: визначення методу GetSalaire веб-сервісу
- рядок 12: визначає метод, який слід виконати, коли виклик методу GetSalaire завершився успішно
- рядок 13: визначає метод, який слід виконати у разі невдалого виклику методу GetSalaire
- рядки 14–18: метод GetSalaire очікує три параметри. Вони визначаються всередині тегу <mx:request> у формі <param1>значення1</param1>. Ідентифікатор param1 не може бути довільним. Необхідно використовувати імена, які очікує веб-сервіс:
![]() |
- у [1] — сторінка веб-сервісу [http://localhost:1077/Service1.asmx]
- на [2] — посилання на тестову сторінку методу [GetSalaire]
- в [3] — параметри, які очікує метод. Саме ці імена слід використовувати як дочірні теги тегу <mx:request>.
Повернемося до оголошення веб-сервісу:
<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>
- рядок 5: параметр ss. Нагадаємо, що під час запуску додатка Flex масив усіх співробітників було збережено у змінній employes типу ArrayCollection.
- employes.getItemAt(i): — це співробітник № i з масиву
- employes.getItemAt(i).SS — номер соціального страхування цього співробітника.
- cmbEmployes.selectedIndex — це номер елемента, вибраного у комбінованому списку співробітників cmbemployes.
Як же з вищенаведеного зрозуміти, що SS — це номер соціального страхування працівника? Для цього потрібно повернутися до відповіді, надісланої методом GetAllIdentitesEmployes:
![]() |
- у [1], сторінка веб-сервісу [Service.asmx]
- на [2] — посилання на сторінку тестування методу [GetAllIdentitesEmployes]
- на [3] — тест виконано. Параметри не очікуються.
- у [4]: відповідь XML містить масив співробітників. Саме цей масив було збережено у змінній employes. У [5] видно, що SS дійсно є тегом, який використовується для зберігання номера соціального страхування.
Завершимо розгляд веб-сервісу:
<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>
- рядок 6: кількість відпрацьованих годин буде вказана у змінній heuresTravaillees
- рядок 6: кількість відпрацьованих днів буде надана змінною joursDeTravail
Ці змінні мають бути оголошені в тезі <mx:Script> з атрибутом [Bindable], що дозволяє компонентам MXML посилатися на них (рядки 7–10 нижче).
<mx:Script>
<![CDATA[
...
// дані
[Bindable]
private var employes : ArrayCollection;
[Bindable]
private var heuresTravaillees:Number;
[Bindable]
private var joursDeTravail:int;
...
</mx:Script>
Код управління подіями у вікні змінюється наступним чином:
<mx:Script>
<![CDATA[
import mx.rpc.events.FaultEvent;
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
// дані
[Bindable]
private var employes : ArrayCollection;
[Bindable]
private var heuresTravaillees:Number;
[Bindable]
private var joursDeTravail:int;
private function init():void{
// фіксуються висота та ширина # блоків
employeHeight=employe.height;
employeWidth=employe.width;
// приховуємо певні елементи
hideEmploye();
...
}
private function displayInfosEmploye():void{
// форма
hideEmploye();
// розраховується умовна заробітна плата
heuresTravaillees=0;
joursDeTravail=0;
pam.GetSalaire.send();
}
private function getSalaireCompleted(event:ResultEvent):void{
...
}
private function getSalaireFault(event:FaultEvent):void{
...
}
// часткові види -------------------------------------------------
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>
- рядок 15: метод init, що виконується під час запуску додатка Flex, запам’ятовує висоту та ширину вертикального контейнера employe, щоб мати змогу відновити його (рядки 50–53) після приховування (рядки 45–48).
- рядок 24: метод displayInfosEmploye виконується, коли користувач змінює свій вибір у комбінованому списку співробітників.
- рядок 26: контейнер employe приховується, якщо він був видимий
- рядок 30: метод GetSalaire веб-сервісу викликається асинхронно. Відомо, що він очікує три параметри:
<ss>{employes.getItemAt(cmbEmployes.selectedIndex).SS}</ss>
<heuresTravaillees>{heuresTravaillees}</heuresTravaillees>
<joursTravailles>{joursDeTravail}</joursTravailles>
- рядок 1: параметром ss буде номер SS співробітника, вибраного у списку співробітників
- рядок 2: метод displayInfosEmploye присвоює змінній heuresTravaillees (рядок 28) значення 0
- рядок 3: метод displayInfosEmploye присвоює змінній joursDeTravail значення 0 (рядок 29)
Метод GetSalaireCompleted виконується, якщо метод GetSalaire веб-сервісу завершується успішно:
private function getSalaireCompleted(event:ResultEvent):void{
// приховування повідомлення про помилку
hideMsg();
// отримання відомості про заробітну плату
var feuilleSalaire:Object=event.result;
// відображення
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();
}
- рядок 3: приховується область повідомлення на випадок, якщо вона відображається.
- рядок 5: отримуємо аркуш заробітної плати, повернутий методом GetSalaire
Щоб дізнатися, що саме повертає метод GetSalaire, повернемося на сторінку веб-сервісу:
![]() |
- у [1] — сторінка веб-сервісу [Service.asmx]
- на [2], посилання, яке веде на сторінку тестування методу [GetSalaire]
- в [3], задаються параметри
- у [4] — отриманий результат XML.
Повернемося до методу getSalaireCompleted:
private function getSalaireCompleted(event:ResultEvent):void{
// приховування повідомлення про помилку
hideMsg();
// отримано розрахунковий лист
var feuilleSalaire:Object=event.result;
// відображення
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();
}
- рядок 5: feuilleSalaire=event.result представляє потік XML [4], повернутий методом GetSalaire. Згідно з цим потоком, бачимо, що:
- feuilleSalaire.Employe — це потік XML певного співробітника
- feuilleSalaire.Employe.Nom — це ім’я цього працівника
- ...
- рядки 7–12: потік XML feuilleSalaire використовується для заповнення різних полів контейнера «employe».
- рядок 13: відображається контейнер «employe».
Метод getSalaireFault виконується, якщо метод GetSalaire веб-сервісу завершується з помилкою:
private function getSalaireFault(event:FaultEvent):void{
// відображення повідомлення про помилку
msg.text=event.fault.message;
// форма
showMsg();
}
- рядок 3: повідомлення про помилку event.fault.message вноситься в поле повідомлення
- рядок 5: поле повідомлення відображається
На цьому завершуються зміни, необхідні для цієї нової версії. Після її збереження, якщо вона є синтаксично правильною, у папці [bin-debug] проекту генерується виконувана версія:
![]() |
Вищезазначений файл [main2.html] — це сторінка HTML, яка містить бінарний файл додатка Flex [main2.swf], що буде виконуватися Flash Player.
Ми можемо протестувати цю нову версію:
- веб-сервіс ASP.NET має бути запущений
- необхідно запустити сервер Apache для клієнта Flex
Якщо припустити, що псевдонім [pam-v10-flex-client-webservice], який використовувався в попередній версії, все ще існує, то в браузері слід звернутися до сервера Apache з запитом на URL або [http://localhost/pam-v10-flex-client-webservice/main2.html]:
![]() |
![]() |
- в [1], запитуваний URL
- в [2], комбінований список співробітників
- в [3], змінюємо вибір у списку, щоб викликати подію change
- в [4], отриманий результат: картка Жюстін Лаверті.
14.5. Вигляд № 3
Вигляд № 3 відповідає перевірці правильності заповнення форми. Тут перевіряється лише поле введення «txtHeuresTravaillees». Доки форма заповнена неправильно, кнопка «btnSalaire» залишатиметься неактивною.
Щоб додати цю функцію, ми дублюємо [main2.mxml] у [main3.mxml]:
![]() |
Відтепер ми працюватимемо з [main3.mxml], який ми зробимо додатком за замовчуванням (див. цей концепт, параграф 14.4). Спочатку ми додаємо атрибут до компонента «txtHeuresTravaillees»:
<mx:TextInput id="txtHeuresTravaillees" change="validateForm(event)"/>
Щоразу, коли змінюється вміст поля введення «txtHeuresTravaillees», викликається метод validateForm. Це локальний метод, написаний розробником. У ньому ми могли б перевірити, чи вміст поля введення «txtHeuresTravaillees» дійсно є додатним цілим числом. Ми зробимо це інакше, використовуючи компонент перевірки:
<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"/>
- рядок 1: компонент <mx:NumberValidator> дозволяє перевірити, чи інший компонент містить ціле або дійсне число.
- рядок 1: атрибут id присвоює компоненту ідентифікатор.
- рядок 1: source — це ідентифікатор компонента, який перевіряється компонентом NumberValidator. У цьому випадку перевіряється поле введення «txtHeuresTravaillees».
- рядок 1: property — це ім’я властивості компонента source, яка містить значення, що підлягає перевірці. У підсумку перевіряється значення source.property, у даному випадку — txtHeuresTravaillees.text.
- рядок 2: precision визначає максимальну кількість дозволених десяткових знаків. precision=0 перевіряє, чи введене число є цілим.
- рядок 2: allowNegative вказує, чи дозволено вводити від’ємні числа
- рядок 7: required вказує, чи є поле обов’язковим для заповнення.
Якщо умова перевірки не виконується, біля компонента, що містить помилку, у спливаючому вікні відображається повідомлення про помилку. За замовчуванням ці повідомлення виводяться англійською мовою. Можна самостійно налаштувати ці повідомлення:
- (продовження)
- invalidCharError: повідомлення про помилку, коли текст містить символ, який не може зустрічатися в числі
- precisionError: повідомлення про помилку, коли кількість десяткових знаків не відповідає атрибуту precision
- negativeError: повідомлення про помилку, коли число є від’ємним, хоча встановлено атрибут allowNegative="false"
- requiredFieldError: повідомлення про помилку, коли не введено жодних даних, хоча встановлено атрибут requiredField="true"
- invalidFormatCharsError: повідомлення про помилку, коли текст містить недопустимі символи або має неправильний формат?
Повернемося до компонента «txtHeuresTravaillees»:
<mx:TextInput id="txtHeuresTravaillees" change="validateForm(event)"/>
Метод validateForm у тезі <mx:Script> може виглядати так:
private function validateForm(event:Event):void
{
// підтверджуємо відпрацьовані години
var evt:ValidationResultEvent = heuresTravailleesValidator.validate();
// підтвердження пройшло успішно?
btnSalaire.enabled=evt.type==ValidationResultEvent.VALID;
}
- рядок 4: виконується валідатор «heuresTravailleesValidator». Він повертає результат типу ValidationResultEvent.
- рядок 6: evt.type має тип String і вказує тип події. evt.type має два можливі значення для типу ValidationResultEvent: «invalid» або «valid», що представлені константами ValidationResultEvent.INVALID та ValidationResultEvent.VALID. Якщо у рядку 4 перевірка пройшла успішно, значення evt.type має дорівнювати ValidationResultEvent.VALID. У цьому випадку кнопка btnSalaire активована, інакше вона неактивна.
Цього достатньо для перевірки правильності обліку відпрацьованого часу.
![]() |
Вище наведено результати компіляції проєкту, в результаті якої були створені файли [main3.html] та [main3.swf]. Ми завантажуємо файли URL та [http://localhost/pam-v10-flex-client-webservice/main3.html] у браузері та перевіряємо різні випадки помилок:
![]() |
![]() |
- поле з помилкою має червону облямівку [1, 2, 3], а поле без помилок — синю облямівку [4].
- У [4] слід звернути увагу, що кнопка [Salaire] активна, оскільки кількість відпрацьованих годин є правильною.
14.6. Вигляд № 4
Вигляд № 4 завершує форму розрахунку заробітної плати. Для цього ми дублюємо [main3.xml] у [main4.xml] і відтепер працюємо з main4, який встановлюємо як стандартний (див. параграф 14.4).
![]() |
Зміни, внесені у файли [main4.xml] та [1], такі:
- до подання [2] додано новий вертикальний контейнер для відображення складових заробітної плати працівника
- додано компонент для форматування грошових значень [3]
- відображення складових заробітної плати забезпечується обробником, пов'язаним із подією «клацання» кнопки «btnSalaire».
Вигляд змінюється наступним чином:
![]() |
Новий контейнер побудований за тим самим принципом, що й попередній. Це вертикальний контейнер VBox [V1], що містить чотири горизонтальні контейнери HBox [Hi]. Горизонтальні контейнери від H1 до H3 утворені вертикальними контейнерами, що містять два написи, другий з яких, у свою чергу, розміщений у вертикальному контейнері для задавання кольору фону.
Завдання 1: написати контейнер для заробітної плати. Надалі його будемо називати complements.
Завдання 2: Напишіть методи, що дозволяють приховувати/відображати контейнер complements. Скористайтеся тим, що було зроблено раніше для контейнера employe.
Прив’язуємо обробник до події «click» кнопки «btnSalaire»:
<mx:Button id="btnSalaire" label="Salaire" click="calculerSalaire()"/>
Метод calculerSalaire має такий вигляд:
private function calculerSalaire():void{
// підготовка форми
affichageSalaire=true;
msg.text="";
// параметри розрахунку заробітної плати
heuresTravaillees=Number(txtHeuresTravaillees.text);
joursDeTravail=int(joursTravailles.value);
// запит на заробітну плату до веб-сервісу
pam.GetSalaire.send();
}
- рядок 3: логічне значення affichageSalaire використовується для вказівки, чи потрібно відображати контейнер complements, який відображає елементи заробітної плати. Метод getSalaireCompleted виконується при двох подіях:
- при зміні співробітника у списку співробітників для відображення його даних без заробітної плати. У цьому випадку встановлюється значення affichageSalaire=false.
- під час розрахунку заробітної плати
- рядок 6: текст поля введення txtHeuresTravaillees перетворюється на дійсне число.
- рядок 7: значення інкрементатора joursTravailles перетворюється на ціле число.
- рядок 9: виклик віддаленого методу GetSalaire. Нагадаємо, що цей метод очікує три параметри, серед яких параметри heuresTravaillees та joursDeTravail, ініціалізовані у рядках 6 та 7. Також нагадаємо, що якщо асинхронний виклик методу GetSalaire:
- завершиться успішно, буде викликано метод getSalaireCompleted
- завершиться невдало — буде викликано метод getSalaireFault
Питання 3: доповнити існуючий метод getSalaireCompleted так, щоб він відображав заробітну плату працівника у разі натискання кнопки btnSalaire.
Наразі елементи заробітної плати відображаються без знака євро. Його можна додати в код або використати форматер. Саме це пропонується зараз. Форматер буде таким:
<mx:CurrencyFormatter id="eurosFormatter" precision="2"
currencySymbol="€" useNegativeSign="true"
alignSymbol="right"/>
- рядок 1: id — ідентифікатор форматора, precision — кількість десяткових знаків, які слід зберегти.
- рядок 2: currencySymbol — це валютний символ, який слід використовувати. useNegativeSign вказує, чи слід використовувати знак «-» для від’ємних значень.
- рядок 3: alignSymbol вказує, де розміщувати валютний знак відносно числа.
Цей формат використовується в коді скрипта наступним чином:
- eurosFormatter — ідентифікатор формату, який слід використовувати
- format — метод, який слід викликати для форматування числа. Він повертає рядок символів.
- feuilleSalaire.Indemnites.BaseHeure — це число, яке потрібно відформатувати.
- lblSH — це ім’я компонента типу Text.
Завдання 4: змініть метод getSalaireCompleted так, щоб він використовував форматувач валюти.





























