Fabrication Framework 0.8.7 released!!!

Mój blog od bardzo długiego czasu pozostawał bez nowych treści. Nadszedł jednak czas, chęci i okazja ku temu by to zmienić.

Jestem jednym z Commiter-ów frameworka Fabrication wykorzystywanego do budowy aplikacji Flash/Flex. Zachęcony dynamicznym rozwojem Flex-a pod skrzydłami Apache Teamu postanowiłem wydać wersję frameworka w której będą używane tylko sparkowe komponenty Flex-a.

Oto co zmieniłem:

Fabrication www: Fabricaiton Framework

Zapis zdarzenia do wybranego kalendarza google

Google udostępnia darmową usługę kalendarzy oraz API dzięki któremu można łatwo zapisywać ważne wydarzenia, tworzyć dowolną ilość kalendarzy oraz dzielić się nimi z innym osobami.

Klasy jednego z modułów Zend Framework-a (Zend_Gdata) pozwalają w niezwykle prosty sposób dodać utworzone wydarzenie.

           //logowanie
           $userCal = 'myemail@gmail.com';
           $passCal = 'mypassword';
           $service = Zend_Gdata_Calendar::AUTH_SERVICE_NAME;
           $client = Zend_Gdata_ClientLogin::getHttpClient($userCal,$passCal,$service);

           //Tworzenie wydarzenia
            $gdataEvent = new Zend_Gdata_Calendar($client);

            $event = $gdataEvent->newEventEntry();

            $event->title = $gdataEvent->newTitle('Tytuł');
            $event->where = array($gdataEvent->newWhere('Miejsce'));
            $event->content = $gdataEvent->newContent('Opis wydarzenia');

            $when = $gdataEvent->newWhen();
            $when->startTime = '2011-05-31T18:20:30';
            $when->endTime =  '2011-05-31T19:20:30';
            $event->when = array($when);

            $gdataEvent->insertEvent($event);

Powyższy kod tworzy wydarzenia w domyślnym kalendarzu, ja jednak potrzebowałem, aby wydarzenia były zapisywane do dowolnie wybranego kalendarza na moim koncie google czego wykonanie nie jest już tak oczywiste. Metoda "insertEvent" obiektu "Zend_Gdata_Calendar" przyjmuje w swoim drugim parametrze url, który stanowi klucz do rozwiązania problemu. Do utworzenia odpowiedniego url-a należy użyć identyfikatora kalendarza, który znajdziemy w ustawieniach każdego z nich.

"Ustawienia kalendarza -> Szczegóły kalendarza (zakładka) -> Adres kalendarza"

Konstrukcja całego adresu oraz metoda zapisująca wydarzenie powinna wyglądać następująco:

          $calendarId = "mqfnddswamiq29qmle6mv4edu0%40group.calendar.google.com";

          //magiczny url :)
          $url = 'https://www.google.com/calendar/feeds/'.$calendarId.'/private/full';

          //zapis
          $gdataEvent->insertEvent($event, $url);

CodeIgniter i Open Power Template

Pojawienie się nowej wersji Code Igniter-a (aktualnie 2.0.2) przyciągnęło moją uwagę, postanowiłem bliżej przyjrzeć się temu niewielkiemu frameworkowi.

Przy tworzeniu rozwiązań w języku php wykorzystuję polskim systemem szablonów Open Power Template, niestety po dłuższym szperaniu wśród zasobów internetu nie znalazłem żadych "udokumentowanych" przypadków integracji CI z OPT (najczęściej spotykane przykłady to połączenie CI z systemem szablonów PHPTAL).

Zaraz po powierzchownym zapoznaniu się z CI przystąpiłem do napisania biblioteki, dzięki której OPT zostało wkomponowane w framework. Zaznacze tutaj, że prezentowane rozwiązanie nie zostało przetestowane w środowisku produkcyjnym.

Po ściągnięciu OPT (link wyżej), przeniosłem zawartość folderu "lib" do katalogu frameworka "applicaton/libraries". Następnie zaimplementowałem prostą klasę która inicjalizuję OPT i umożliwia wyrenderowanie ustawionych templatek.

require_once(APPPATH.'libraries/Opl/Base.php');
/**
 * OptLib - simple load Opt_View (template) and render it
 */
class OptLib
{
    /**
     * The OPT view.
     *
     * @var Opt_View
     */
    public $view;

    /**
     * Http header
     *
     * @var Opt_Output_Http
     */
    private $_out;

    /**
     * Path to template folder
     *
     * @var string
     */
    private $_templatePath;

    public function  __construct()
    {
        Opl_Loader::loadPaths(array('directory' => './',
				  'libraries' => array('Opl' => APPPATH.'libraries/Opl/',
				  'Opt' => APPPATH.'libraries/Opt/')));
        Opl_Loader::setHandleUnknownLibraries(false);
        Opl_Loader::register();

        $this->_templatePath = APPPATH.'views/';

        $this->_initView();
    }

    /**
     * Initializes the Opt_View object for the action.
     */
    private function _initView()
    {
        try
        {
            $tpl = new Opt_Class();
            $tpl->sourceDir = $this->_templatePath;
            $tpl->compileDir = APPPATH.'cache/';
            $tpl->contentType = Opt_Output_Http::XHTML;
            $tpl->compileMode = Opt_Class::CM_REBUILD;
            $tpl->charset = 'utf-8';
            $tpl->setup();

            $this->_out = new Opt_Output_Http();
            $this->_out->setContentType();

            $this->view = new Opt_View('layout.tpl');
            $this->view->modules = array();
        }
        catch(Opt_Exception $exception)
        {
            Opt_Error_Handler($exception);
        }
    } 

    /**
     * Render template file and show in browser
     *
     * @param string $templateName Template file name or path
     * @param mixed $data name/value pair data for current template
     */
    public function render($templateName, $data)
    {
        $this->view->modules = array();
        if (file_exists($this->_templatePath.$templateName))
        {
            $moduleView = new Opt_View($templateName);
            if ($data)
            {
                foreach ($data as $k => $v)
                {
                    $moduleView->assign($k, $v);
                }
            }

            $this->view->modules[] = array('view' => $moduleView);
        }

        $this->_out->render($this->view);
    }
}

W funkcji "_initView" domyślnie tworzony jest widok główny, który zawiera sekcję o nazwie "modules" (poniżej fragment kodu templatki)

<body>
     <opt:section name="modules">
                <opt:include from="modules">
                    <p>Nie znaleziono templatek.</p>
                </opt:include>
     </opt:section>
</body>

By móc korzystać z biblioteki należy ją w pierwszej kolejności załadować np. w konstruktorze kontrolera.

class My_Controller extends CI_Controller
{
	public function __construct()
	{
            parent::__construct();

            $this->load->library('optlib');
	}
}

Wyświetlenie zawartości templatek odbywa się za pomocą funkcji "redner", wewnątrz której dodawana jest do sekcji modules wybrana templatka, wraz z ewentualnymi danymi które chcemy do niej wstrzyknąć.

$this->optlib->render('mytemplate.tpl', array('mytext' => 'Mój tekst'));

Jak widać metchanizm dodawania własnych bibliotek do CI jest dość prosty i wygodny. :)

Mój pierwszy raz na 4Developers

Mam za sobą pierwsze "odwiedziny" na corocznej konferencji 4Developers. Postanowiłem pokusić się o małe podsumowanie w dość nietypowej formie. Z różnych przyczyn nie zdołałem oddać swojej ankiety oceniającej całe wydarzenie. Poniżej prezentuję niektóre pytania wraz z moimi odpowiedziami.

  1. Jakie zagadnienia chciałbyś, aby zostały poruszone na następnej konferencji 4Developers?

    Proponował bym zagadnienia związane z technologią Adobe Flex w połączeniu z Php.

  2. Co podczas konferencji 4Developers podobało Ci się najbardziej?

    Kompetentna obsługa całej imprezy – mimo drobnych problemów technicznych organizatorzy zdołali opanować i utrzymać konferencje w wyznaczonych ramach czasowych.
    Podobała mi się również płeć piękna wśród obsługi. :)

  3. Wymień 3 najlepsze wykłady w których uczestniczyłeś:

    • "Wdrażanie Continuous Integration w praktyce" – Sebastian Marek

    • "Nowe bardziej racjonalne podejście do warstw" – Sławomir Sobótka

    • "Zend Framework 2.0 rządzi" – Juozas Kaziukenas

  4. Wymień 3 najsłabsze wykłady, w których uczestniczyłeś: (Tutaj pozwole sobie wymienić tylko jeden który najmniej mi przypadł do gustu)

    • "Uprość zarządzanie zależnościami między aplikacjami trzecimi, a swoim projektem" – Stephan Hochdoerfer

Wyjazd uważam za bardzo udany, generalnie brak uwag w strone organiztorów. Dobrze wydane pieniądze, dobry dobór prelegentów na ścieżce PHP i nie tylko. :) Tak trzymać! Do zobaczenia za rok. :)

Fabrication na facebook

Framework fabrication doczekał się własnej strony na facebook-u oraz loga. :) Zachęcam do odwiedzin i przyłączenia do facebook-owego grona gdzie, Rafał będzie na bieżąco informował o zmianach zachodzących w fabrication i nie tylko. :)

W zakładce "Dyskusje", został założony temat w którym można podzielić się ewentualnymi pomysłami: "co mogło by się zmienić w frameworku" lub "co nowego mogło by zostać dodane".

Link do strony tutaj.

Logo fabrication:



logo_fabrication

Logo zostało wykonane przez Pawła Nejmana. :)

Reakcje i itemrenderer-y w Fabrication

Framework fabrication posiada w swym arsenale ciekawy mechanizm odpowiadający za rejestrację zdarzeń dla komponentów obsługiwanych przez mediatory (klasy komunikujące się z komponentami wizualnymi). Reakcje, bo o nich tutaj mowa są obiektami mającymi za zadanie przypisanie do obiektu "handlera" – funkcji, która zostanie wykonana gdy wystąpi wybrane zdarzenie.

W prezentowanym wpisie chciałbym się jednak skupić nie na samych zaletach reakcji (sposób implementacji i wykorzystania), ale o specyficznej sytuacji w której zachodzi potrzeba obsługi poprzez Reakcje zdarzeń zachodzących w itemrenderer-ach kontrolek flex-owych.

Załóżmy, że potrzebujemy kontrolki DataGrid w której jedna z kolumn powinna zawierać CheckBox-a. Kontrolka zostaje umieszczona w kontenerze Group dla którego rejestruje mediator. CheckBox posiada zdarzenie "change", którego obsługą jesteśmy zainteresowani wewnątrz mediatora.

W chwili obecnej sytuacja implementacyjnie wygląda następująco

Komponent mediatora

<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
         xmlns:s="library://ns.adobe.com/flex/spark"
         xmlns:mx="library://ns.adobe.com/flex/mx">
    <s:layout>
        <s:VerticalLayout horizontalAlign="left"
                          gap="10"/>
    </s:layout>
    <mx:DataGrid id="dg"
                 width="400"
                 height="250">
        <mx:columns>
            <mx:DataGridColumn headerText="Name"
                               dataField="name"/>
            <mx:DataGridColumn headerText="Surname"
                               dataField="surname"/>
            <mx:DataGridColumn headerText="Details"
                               textAlign="center"
                               width="100"
                               itemRenderer="main.view.components.DgItemRenderer"/>
        </mx:columns>
    </mx:DataGrid>
</s:Group>

Itemrenderer DataGrid-a

<s:MXDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
                          xmlns:s="library://ns.adobe.com/flex/spark">

    <s:CheckBox height="25"
                horizontalCenter="0"/>
</s:MXDataGridItemRenderer>

Mediator

public class PersonsListMediator extends FlexMediator
{
        /**
         * Mediator name
         */
        public static const NAME:String = "PersonsListMediator";

        public function PersonsListMediator(viewComponent:PersonsList)
        {
            super(NAME, viewComponent);
        }
        /**
         * Component
         */
        public function get personsList():PersonsList
        {
            return viewComponent as PersonsList;
        }
}

Mając do dyspozycji klasę mediatora możemy rejestrować Reakcje dla zdarzeń kontenera Group oraz wszystkich kontrolek które zawiera.

Jednak rejestracja Reakcji dla CheckBox-a znajdującego się w kolumnie DataGrid-a wymaga nieco więcej "gimnastyki". By mediator "wiedział" o zajściu zdarzenia w itemrenderer należy stworzyć własny even-t w kontrolce przypisanej do mediatora.

<fx:Metadata>
        /**
         *  Declare item renderer events
         */
        [Event(name="selectedChanged", type="flash.events.Event")]
</fx:Metadata>

Następnie etap to powiadomienie komponentu mediatora, że w itemrender zaszło zdarzenie "change" CheckBox-a.
Cały "trick" plega na uruchomieniu zdarzenia "selectedChanged" z włączonym tzw. bąbelkowaniem. Dzięki temu metoda obsługująca zdarzenie "selectedChanged" zostaje wykonana i osiągamy swój cel główny.


<s:MXDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
                          xmlns:s="library://ns.adobe.com/flex/spark">

    <s:CheckBox height="25"
                horizontalCenter="0"
                change="onChangeCheckBox(event)"/>
    <fx:Script>
        <![CDATA[
        /***
         * Create event with bubbles and dispatch it
         *
         * @param Event event
         */
        private function onChangeCheckBox(event:Event):void
        {
            dispatchEvent(new Event("selectedChanged", true));
        }
       ]]>
    </fx:Script>
</s:MXDataGridItemRenderer>

W mediatorze rejestracja reakcji dla zdarzenia "selectedChange" czyli "change" CheckBox-a odbywa się poprzez utworzenie metody zgodnie z zaleceniami na stronie projektu.

public function reactToPersonsList$SelectedChanged(event:Event):void
{
     Alert.show("selectedChange event");
}

Zaprezentowany powyżej przykład współpracy Reakcji i itemrenderer-ów został także przeze mnie opisany na stronie projektu, gdzie udostępniłem nieco obszerniejszy kod przykładu oraz możliwość jego uruchomienia – Zapraszam. :)

Małe sukcesy

Letnie upały źle wpływają na zakamarek mojej głowy, który odpowiada za me blogowe poczynania. :) W kwestii programowania nie mogę narzekać na brak zajęć w ostatnim czasie udało mi się zakończyć pracę nad moim portfolio. Na codzień raczej niewiele zajmuję się bezpośrednio kodowaniem stron od początku do końca, więc nie obyło się bez pomocy bardziej doświadczonych kolegów. ;) Jest w nim jak narazie niewiele prac, umieściłem tylko te, które moim zdaniem były najbardziej pracochłonne.

Kilka miesięcy temu w swojej pracy zacząłem wykorzystywać nowy framework Tequila, główny pomysłodawca oparł jego działanie na bazie już istniejących rozwiązań PureMVC oraz Fabrication. Twórca Fabrication zaprzestał pracy nad jego rozwojem – Rafałowi udało się z nim skontaktować i obecnie to on jest głównym programistą czuwającym nad rozbudową tego popularnego frameworka. Jak się można było spodziewać wszelkie dobrodziejstawa, które stworzył w Tequil-i zostały całkowicie przeniesione do Fabrication (lista dobrodziejstw tu) :). Od samego początku śledziłem oraz starałem się wykorzystywać przeniesione z Tequili do Fabrication usprawnienia. Zaowocowało to tym że Rafał postanowił dodać mnie do projektu Fabrication. :)

Za co mu bardzo dziękuję! Mam nadzieję, że uda mi się wnieść coś dobrego do tworzonych przez niego rozwiązań.

SystemTrayIcon i DoubleClick w Adobe Air

Niedawno rozpocząłem pracę nad aplikacją w adobe air. Jedną z niewielkich funkcjonalności była minimalizacja aplikacji do postaci ikonki w tray-u, oraz przywrócenie jej okna po dwukrotnym kliknięciu. Sam proces wczytania oraz minimalizacji nie stanowił problemu, ale ponowne pokazanie okna po dwukrotnym kliknięciu w ikonę niestety sprawiło mi nieco trudności.

Załadowana ikona w tray-u reprezentowana jest przez klasę SystemTrayIcon, która udostępnia szereg zdarzeń, niestety wśród nich brakuje obsługi podwójnego kliknięcia. Do opisywanej sytuacji pasuję przysłowie "Jak się nie ma co się lubi, to się lubi co się ma"
- innymi słowy postanowiłem wykorzystać to co mam dostępne czyli pojedyncze kliknięcie. ;)

Klasa zdarzenia "DoubleClick" dla mojej ikonki:

public class ExtendedSystemTrayIconEvent extends ScreenMouseEvent
{
	 public static const DOUBLE_CLICK:String = "doubleClick";

	 public function ExtendedSystemTrayIconEvent(type:String, bubbles:Boolean=false,
						   cancelable:Boolean=false, screenX:Number=undefined,
						   screenY:Number=undefined, ctrlKey:Boolean=false,
					    altKey:Boolean=false, shiftKey:Boolean=false,
						   buttonDown:Boolean=false, commandKey:Boolean=false,
						   controlKey:Boolean=false)
	 {
		   super(type, bubbles, cancelable, screenX, screenY,
		   ctrlKey, altKey, shiftKey, buttonDown, commandKey, controlKey);
	 }
}

Klasa dostarczająca obsługę zdarzenia:

[Event(name="doubleClick", type="ExtendedSystemTrayIconEvent"]
/**
*SystemTrayIcon DoubleClick
*This class provide double click on tray icon
*
* @author Piotr Zarzycki
*
*/
public class SystemTrayIconWraper extends EventDispatcher
{
   private var _systemTrayIcon:SystemTrayIcon;
   private var _clickCounter:int = 0;
   private var _timer:Timer;

   public function SystemTrayIconWraper(systemTrayIcon:SystemTrayIcon)
   {
		   _systemTrayIcon = systemTrayIcon;
		   _timer = new Timer(1000, 1);
		   _timer.addEventListener(TimerEvent.TIMER_COMPLETE,
                            onTimeComplete);

		   _systemTrayIcon.addEventListener(ScreenMouseEvent.CLICK,
                            onClickTrayIcon);
   }

   public function onClickTrayIcon(event:ScreenMouseEvent):void
   {
		   if (!_timer.running)
		   {
			   _timer.start();
		   }
		   _clickCounter++;
		   if (_clickCounter > 1)
		   {
			      _systemTrayIcon.dispatchEvent(
              new ExtendedSystemTrayIconEvent("doubleClick",
                     event.bubbles, event.cancelable, event.screenX,
                     event.screenY, event.ctrlKey, event.altKey,
                     event.shiftKey, event.buttonDown, event.commandKey,
                     event.controlKey));

			      _clickCounter = 0;
		   }
   }

   override public function addEventListener(type:String, listener:Function,
                                   useCapture:Boolean=false, priority:int=0,
                                   useWeakReference:Boolean=false):void
   {
		      _systemTrayIcon.addEventListener(type, listener, useCapture, priority,
                                          useWeakReference);
   }

   private function onTimeComplete(event:TimerEvent):void
   {
		   _clickCounter = 0;
		   _timer.reset();
   }
}

Klasa "SystemTrayIconWraper" dziedziczy po klasie "EventDispatcher", obsługuję zdarzenie "CLICK" dla obiektu SystemTrayIcon dostarczonego w jej konstruktorze oraz inicjalizuję klasę "Timer" wartością 1 sekundy. Dodatkowo w jej wnętrzu tworzę zmienną przechowującą ilość kliknięć na ikonkę tray-a – wartość większa niż jeden oznacza podwójny klik. Przy pierwszy klik-u zostaje uruchomiony timer i zwiększony licznik kliknięć. Jeżeli w ciągu sekundy nie nastąpi kolejne kliknięcie licznik i timer są resetowane.

Na koniec pozostaje pytanie – Dlaczego zabrakło obsługi właśnie tego zdarzenia w klasie SystemTrayIcon?

EDIT (08-08-2010): Do powyższego rozwiązania wkradł się niewielki błąd – jest to dość późna edycja, ale wcześniej brak chęci i czasu na blogowe poczynania. W metodzie „onClickTrayIcon” wywołanie event-a „doubleClick” odbywa się na instancji obiektu „SystemTrayIcon”. Przesłonięta została także metoda „addEventListener”.

Błąd „Variable number of arguments is not supported for services”

W programowaniu dość istotną kwestią jest komentowanie kodu, mam na tym punkcie lekkiego fioła.;) Tworząc funkcję w serwisie udostępniającym dane jak zawsze przystąpiłem do ob-komentowania parametrów i opisania samego działania funkcji.

/**
 * Test function
 *
 * @param string $name
 * @param string $surname
 * @return array
 */
 public function testFunction($name, $surname)
 {
      return $name.' '.$surname;
 }

Po całym rytuale komentowania doszedłem do wniosku, że nie będzie mi potrzebny jeden z parametrów. Radośnie usunąłem go, po czym przystąpiłem do sprawdzenia działania funkcji w ZAmfBrowser otrzymałem błąd o sygnaturze:

PHP Fatal error: Uncaught exception ‘Zend_Server_Reflection_Exception’ with message ‘Variable number of arguments is not supported for services (except optional parameters). Number of function arguments must correspond to actual number of arguments described in a docblock.’

Dość długo zastanawiałem się, co jest nie tak, a to, dlatego, że w pośpiechu zwróciłem uwagę tylko na pierwsze zdanie – drugie z kolei mówi mi o wiele więcej.

Ilość argumentów funkcji musi odpowiadać ilości argumentów opisanych
w docblock-u.

Jednak na to wszystko zwrócił mi uwagę kolega z pracy, który zerknął na mój kod. Morał z całego "zajścia":

  • Analizuj błędy w całości, bo może ich rozwiązanie kryje się na samym końcu opisu otrzymanego wyjątku
  • Czasami warto aby ktoś spojrzał na Twój kod "świeżym" okiem, to może przynieść nie tylko rozwiązanie, ale niejednokrotnie poprawę funkcjonalności

Dostęp do itemrenderer-ów w Spark DataGroup

Czwarta odsłona Flex SDK przyniosła ze sobą nowe rodzaje kontenerów ułatwiających rozmieszczanie komponentów w aplikacjach flex-owych. Jednym z nich jest DataGroup. Nie chcę tutaj opisywać możliwości kontenera tylko przedstawić sposób w jaki uzyskałem dostęp do utworzonych w moim DataGroup itemrenderer-ów.

Mój itemrenderer wyświetla imię i nazwisko na podstawie danych zawartych w obiekcie "PersonVo".

Klasa PersonVo.

public dynamic class PersonVo
{
		public var firstName:String;
		public var surname:String;

		public function PersonVo(firstName:String = null,
					surname:String = null)
		{
			this.firstName = firstName;
			this.surname =surname;
		}
}

Kod itemrenderer-a

<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
		xmlns:s="library://ns.adobe.com/flex/spark"
		xmlns:mx="library://ns.adobe.com/flex/mx"
		autoDrawBackground="true">
	<s:HGroup gap="5"
			  height="100%">
		<s:Label id="firstName"
			 text="{data.firstName}"/>
		<s:Label id="surname"
			 text="{data.surname}"/>
	</s:HGroup>
</s:ItemRenderer>

Dostęp do każdego utworzonego obiektu itemrenderera uzyskuję rejestrując metodę dla zdarzenia "rendererAdd". W jej argumencie zostaje dostarczony obiekt "event" typu "RendererExistenceEvent", który to zawiera instancję itemrenderera. Wszystkie obiekty itemrenderer-ów umieszczam w tablicy i udostępniam na zewnątrz kontenera DataGroup poprzez publiczną właściwość.

DataGroup z przechowanymi obiektami itemrenderer-ów.

<s:DataGroup xmlns:fx="http://ns.adobe.com/mxml/2009"
	        xmlns:s="library://ns.adobe.com/flex/spark"
	        xmlns:mx="library://ns.adobe.com/flex/mx"
                   itemRenderer="dgControls.DgControlRenderer"
	        rendererAdd="onRendererAdd(event)">
	<fx:Script>
		<![CDATA[
			import spark.events.RendererExistenceEvent;
			private var _itemRenderers:Array = [];

			/**
			 * Array of itemrenderers
			 * */
			public function get itemRenderers():Array
			{
				return _itemRenderers;
			}

			/**
			 * Add renderer to array
			 * */
			protected function onRendererAdd(event:RendererExistenceEvent):void
			{
				_itemRenderers.push(event.renderer);
			}
		]]>
	</fx:Script>
</s:DataGroup>

Do dataprovidera kontenera DataGroup dostaczyłem następującą tablicę oraz przeprowadziłem prostą iterację wraz ze zmianą właściwości wewnątrz itemrenderera. W zasadzie było to dość proste, ale czy to jedyne rozwiązanie? ;)

Tablica elementów "dataProvidera" w DataGroup.

var dpDataGroup:ArrayCollection = new ArrayCollection([
						new PersonVo("Piotr", "Zarzycki"),
						new PersonVo("Marian", "Zakrzewski"),
						new PersonVo("Damian", "Zarzycki")
					]);

Zmiana właściwości obiektów itemrenderer-ów.

var count:int = dg.itemRenderers.length;

for(var i:int = 0; i < count; i++)
{
					var dgRenderer:DgControlRenderer = dg.itemRenderers[i];
					dgRenderer.firstName.text = "Ola";
					dgRenderer.surname.text = "O.";
}