Полезные ссылки

Построитель стилей

Природа не понимает шуток. Она всегда честна, всегда серьёзна, всегда сурова. Она всегда права, а ошибки и промахи делают только люди. Человек, который относится к природе с пренебрижением, не способен её оценить, и только понимающему, чистому и правдивому, она покоряется и открывает свои тайны.
Иоган Вольфнг фон Гёте
Создание Flex-приложений c использованием Parsley. Часть 2, обмен данными
28.09.2009 17:32

В предыдущей статье, я начал рассказ о технологии, которая позволяет гибко конфигурировать Flex приложение, где рассмотрел первый аспект, а именно связывание различных компонентов приложения в одно целое. В данной статье хочу подробнее остановиться на организации модели обмена данными в приложении созданном с использованием Parsley.

Чтобы создать действительно отторжимые модули, в приложении должна быть создана грамотная система обмена данными. Как мне кажется в Parsley есть всё, чтобы построение такой системы было максимально удобным и лёгким в использовании.
В Parsley предусмотрено два варианта инициализации процесса передачи данных и три варианта получения данных. Рассмотрим каждый из них. Начнём именно с вариантов инициализации передачи данных.
Первый вариант использует уже существующий механизм Flex -dispatchEvent. Но к этому добавляется один момент - мы должны указать Parsley, какие события он должен "слушать". Делается это добавлением мета-нформации в начале класса, сам класс должен, естественно расширять EventDispatcher. Рассмотрим данный вариант на примере класса ContactPanel.
<?xml version="1.0" ?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns="ru.gubber.sample.flex.view.component.*" addedToStage="init(event)">

<mx:Metadata>
[ManagedEvents("createContactEvent, showContactEvent, copyContactEvent, deleteContactEvent,showListEvent")]
</mx:Metadata>
<mx:Script><![CDATA[
import mx.collections.ArrayCollection;

import ru.gubber.sample.flex.model.Contact;
import ru.gubber.sample.flex.view.event.ApplicationEvent;

[MessageBinding(messageProperty="list",type="ru.gubber.sample.flex.controller.massages.ContactListMessage")]
[Bindable]
public var list:ArrayCollection;
private var inited:Boolean = false;

private function init(event:Event):void {
if (!inited) {
inited = true;
dispatchEvent(new Event('configureIOC', true));
showList();
}
}

private function showList():void {
dispatchEvent(new ApplicationEvent(ApplicationEvent.SHOW_LIST_EVENT))
}

private function createNew():void {
dispatchEvent(new ApplicationEvent(ApplicationEvent.CREATE_CONTACT_EVENT))
}

private function createCopy():void {
dispatchEvent(new ApplicationEvent(ApplicationEvent.COPY_CONTACT_EVENT, table.selectedItem as Contact))
}

private function makeDelete():void {
dispatchEvent(new ApplicationEvent(ApplicationEvent.DELETE_CONTACT_EVENT, table.selectedItem as Contact))
}

private function showContact():void {
dispatchEvent(new ApplicationEvent(ApplicationEvent.SHOW_CONTACT_EVENT, table.selectedItem as Contact))
}

[MessageHandler(selector="updateContactSuccess")]
public function saveContactHandler():void {
showList();
}

]]></mx:Script>
<PagedDataGrid id="table" pageSizes="[10, 20, 30, 50, 100]" origData="{list}" width="100%" height="100%">
<columns>
<mx:DataGridColumn dataField="id" headerText="№"/>
<mx:DataGridColumn dataField="name" headerText="Имя"/>
<mx:DataGridColumn dataField="email" headerText="e-mail"/>
<mx:DataGridColumn dataField="phone" headerText="Телефон"/>
</columns>
</PagedDataGrid>
<mx:HBox width="100%" horizontalAlign="center">
<mx:LinkButton label="Добавить" click="createNew()"/>
<mx:LinkButton label="Обновить" enabled="{table.selectedItem != null}" click="showContact()"/>
<mx:LinkButton label="Копировать" enabled="{table.selectedItem != null}" click="createCopy()"/>
<mx:LinkButton label="Удалить" enabled="{table.selectedItem != null}" click="makeDelete()"/>
</mx:HBox>
<ContactForm height="140" width="100%"/>
</mx:VBox>


В данном случае код приведён без "купюр". Объявление необходимых в обработке событий описывается в 6 строке. В то же время генерация событий происходит в с 27 строки по 45. В каждом из методов не делается ровным счётом ничего, кроме генерации события с тем набором данных, которые надо передать в другой компонент.
Второй метод инициализации процесса передачи данных рассмотрим на примере класса LocalContactService.
package ru.gubber.sample.flex.controller.services {
...

public class LocalContactService implements IContactService{

[MessageDispatcher]
public var dispatcher:Function;
private var connection:SQLConnection = new SQLConnection();
private var dbFile:File;

public var fileName:String;
private var exists:Boolean = true;

public function LocalContactService() {
super();
}

[PostConstruct]
public function init() : void {
if (!fileName) {
fileName = "default.db";
exists = false;
}
dbFile = File.applicationStorageDirectory.resolvePath(fileName);
}

[PreDestroy]
public function dispose() : void {
if ((connection) && (connection.connected)) {
connection.commit();

}
connection.close();
}

public function tryBD():void {
if ((!exists) && (!dbFile.exists))
dispatcher(new ContactMessage(ContactMessage.DB_ERROR_MESSAGE));
else {
try {
connection.open(dbFile, SQLMode.UPDATE);
connection.addEventListener(SQLErrorEvent.ERROR, function (event:SQLErrorEvent):void {
dispatcher(new ContactMessage(ContactMessage.DB_ERROR_MESSAGE));
});

var stm:SQLStatement = new SQLStatement();

stm.sqlConnection = connection;
stm.text = "SELECT count(*) FROM CONTACTS";
stm.addEventListener(SQLErrorEvent.ERROR, function (event:SQLErrorEvent):void {
dispatcher(new ContactMessage(ContactMessage.DB_ERROR_MESSAGE));
});
stm.addEventListener(SQLEvent.RESULT, function (event:SQLEvent):void {
dispatcher(new ContactMessage(ContactMessage.DB_SUCCESS_MESSAGE));
});
stm.execute();

} catch(e:Error) {
Alert.show(e.message);
dispatcher(new ContactMessage(ContactMessage.DB_ERROR_MESSAGE));
}
}
}
...

}
}


В данном примере стоит обратить внимание на 6 и 7 строку, где внедряется функция, которая будет инициировать процесс передачи сообщения в другой модуль. В данном примере это происходит на 38, 51, 54 и 60 строках, где генерируется событие об успешном или ошибочном завершении запроса к таблице в нашей БД. В данном случае стоит отметить, что класс ContactMessage НЕ является наследником класса Event.
Так же можно отметить внимание на директивы на 18 и 27 строках, которые используются для организации жизненного цикла компонента. В первом случае указывается метод, который будет выполнятся после создания этого объекта, второй метод будет выполнятся перед тем, как будет выгружен из контекста.
Теперь, когда мы умеем отправлять сообщения с данными, нам надо научиться принимать эти данные.
Первый способ - прямое связывание данных из сообщения/события с определённым объектом(MessageBinding). Для этого обратимся к строчкам 21-23 класса ContactForm, где используется данный вариант отслеживания данных.
[MessageBinding(messageProperty="item", type="ru.gubber.sample.flex.controller.massages.ContactMessage")]
[Bindable]
public var contact:Contact;



Директива MessageBinding, сообщает, что эта переменная будет принимать то же значение, что и свойство item для любого объекта ContactMessage, которое было инициализировано одним способов передачи данных, описанных ранее. Что приводит нас к мысли, что надо чётко понимать - использование этого варианта чревато ошибками, когда событие данного типа генерируется для отличных от установления данной переменной целей. С другой стороны его можно использовать когда данные не требуют дополнительной обработки.
Второй вариант - обработка сообщений (MessageHadler). Для этого обратимся к 19-23 строкам класса ContactAction.
[MessageHandler(selector="tryDbEvent")]
public function tryDBHandler(contMessage:ApplicationEvent):void {
service.tryBD();
}





Первое, что надо иметь в виду, что так же как и связывание объектов, обработчик сообщений привязывается по КЛАССУ сообщения/события. Другими словами если использовать синтаксис

[MessageHandler]
public function myHandler(contMessage:ApplicationEvent):void {
service.tryBD();
}

Тогда функция myHandler будет обрабатывать ВСЕ события класса ApplicationEvent. Если же необходимо обрабатывать строго определённые события, то для этого так же как и при связывании используется механизм выбора. Только в данном случае есть небольшое отличие при обработке событий (наследники Event) и собственных сообщений (не наследники Event). Для событий поле, по которому происходит выбор - это поле type. В то же время для своих сообщений вы это поле должны указать сами. используя директиву [Selector], как это сделано в классе ContactMessage.

[Selector]
public var type : String;


Если мы вернёмся к описанию метода tryDBHandler. То теперь мы понимаем, что данный метод должен обрабатывать события ApplicationEvent, у которых поле type принимает значение "tryDbEvent".

Последний метод обработки событий - перхватчик события (MessageInterceptor). В данном примере я его не использовал. Суть данного метода сводиться к тому, что перед тем как событие будет обработано либо первым либо вторым способом это событие можно перехватить, обработать и самое главное - отправить событие дальше в обработку или запретить его дальнейшую обработку. Этот метод, как и несколько других моментов, которые не попадут в текущую серию заметок, я постараюсь рассмотреть отдельно.

Следующая статья будет завершать краткий обзор библиотеки Parsley. В нём я постараюсь изложить своё видение того, как можно грамотно организовать приложение.

Исходные коды можно взять из SVN репозитария https://gubber.ru/svn/samples/tag/parsley1/parsley/. Логин и пароль для доступа test/test.

Комментарии
Добавить новый Поиск
Оставить комментарий
Имя:
Email:
 
Веб-сайт:
Тема:
UBB-Код:
[b] [i] [u] [url] [quote] [code] [img] 
 
 
:angry::0:confused::cheer:B):evil::silly::dry::lol::kiss::D:pinch:
:(:shock::X:side::):P:unsure::woohoo::huh::whistle:;):s
:!::?::idea::arrow:
 

!joomlacomment 4.0 Copyright (C) 2009 Compojoom.com . All rights reserved."