mercoledì 12 novembre 2014

TFDDataSetProvider: un supporto a design time per Datasnap e FireDAC (FireDACJSONReflect)

Introduzione

Con Delphi XE5 Update 2, è stata introdotta la unit FireDACJSONReflect che rappresenta una prima occasione di integrazione di FireDAC con DataSnap.
Tale unit permette di serializzare uno o più dataset FireDAC e restituirli in un'unica chiamata DataSnap REST. Inoltre sono presenti diverse funzionalità utili allo sviluppo di una applicazione multitier dataset-oriented quali ad esempio:
- l'estrazione lato client del delta dei dataset;
- l'applicazione delle modifiche lato server una volta ricevuti i delta dai client.

Personalmente ritengo FireDAC una delle migliori tecnologie aggiunte a Delphi (e RAD Studio) negli ultimi anni e sono stato molto felice di vedere introdotta la unit FireDACJSONReflect.
Chi di voi ha usato DataSnap nella sua accezione dbExpress (con il ClientDataSet e il DataSetProvider, per intenderci), sicuramente avrà notato che attualmente è difficile avere un supporto design time nello sviluppo del client di una applicazione DataSnap+FireDAC.
Di fatti, come spiegato egregiamente anche da Cary Jensen nella sua sessione FireDAC di EuroDevCon 2014 (EKON 18), l'approccio d'uso di FireDAC con DataSnap differisce dal precedente (DataSnap + dbExpress) in quanto i dati sono restituiti dal server come risposta a chiamate a metodi (e non affacciati all'esterno tramite IAppServer e l'uso dei TDataSetProvider).

La possibilità di avere il dataset pieno durante la progettazione della nostra applicazione (cioè a design-time) è fondamentale se vogliamo sfruttare a pieno le funzionalità RAD di Delphi e in particolar modo questa esigenza mi sembra importante in una applicazione FireMonkey in cui si voglia sfruttare la tecnologia dei (Visual) LiveBinding.  

Sviluppo di un componente (VCL e FMX) per aggiungere un supporto design-time a DataSnap+FireDACJSONReflect

Ho pensato che:
  1. sfruttando la possibilità di usare la REST Client Library per effettuare una chiamata REST ad un server DataSnap;
  2. catturando il risultato JSON di un metodo che ritorni un'istanza di TFDJSONDataSets;
  3. usando il meccanismo di unmarshaling presente in DBXJSONReflect;
  4. e appoggiando i dati ad una TFDMemTable (che poi è lo stesso di quanto si faccia attualmente a run-time con una applicazione client DataSnap+FireDACJSONReflect)
sarebbe stato semplice ottenere un componente in grado di riempire a design-time una TFDMemTable ed effettivamente così è stato.
Ho creato il componente TFDDataSetProvider (una cinquantina di righe di codice che potete vedere qui) che potete aggiungere alle vostre form (o datamodule) VCL o FireMonkey (desktop o mobile) e, grazie al relativo component editor, recuperare i dati dal server DataSnap per poi travasarli in una o più TFDMemTable per le vostre esigenze.

Demo

A) Creare una DataSnap Server REST Application con FireDACJSONReflect


In sostanza, assumiamo di avere un metodo come il seguente:

function TServerMethods1.GetData: TFDJSONDataSets;

B) Creare una DataSnap Client Application

Potete creare una nuova applicazione e decidere o meno se usare il wizard di creazione di un DataSnap REST Client Module e farvi generare le classi proxy per l'invocazione dei metodi del server DataSnap.


Ma per provare il mio componente, non è strettamente necessario. Infatti, non volevo includere nel componente un livello di complessità tale da rigenerare automaticamente le classi proxy per ogni eventuale progetto DataSnap server con cui utilizzarlo. Ho pensato di sfruttare l'anima REST (http+JSON) e quindi l'unica cosa che vi servirà è appunto un'istanza del componente TFDDataSetProvider (dovrete installarlo, installando i due package che ho preparato).


Il componente, ingloba i componenti necessari ad eseguire la chiamata REST (TRESTClient e TRESTRequest, della REST Client Library, introdotta con XE5) e quindi (con il server DataSnap in esecuzione, fuori dall'IDE) non occorre altro che configurare la richiesta ad esempio nel seguente modo (considerando il metodo di esempio TServerMethods1.GetData illustrato prima):

FDDataSetProvider1.RESTClient.BaseURL := 'http://localhost:8080/datasnap/rest/TServerMethods1/';

FDDataSetProvider1.RESTRequest.Resource := 'GetData';

In questo modo il componente saprà come contattare il vostro server DataSnap ed invocare il metodo GetData via REST. Potete eseguire quest'azione direttamente nell'IDE facendo click con il pulsante destro sul componente e scegliendo la voce di menù contestuale: "Retrieve data from server".
Una dialog vi confermerà se la chiamata REST è andata a buon fine e quanti dataset (con relativi nomi) sono stati scaricati dal server.

Ora, se aggiungiamo alla nostra form una TFDMemTable (es. FDMemTable1) e impostiamo la proprietà TargetDataSet del nostro FDDataSetProvider1 a FDMemTable1.
Se ora clicchiamo nuovamente sul FDDataSetProvider1 (con il pulsante destro), noteremo che per ogni dataset scaricato è presente una voce di menù che ci permette di travasare i dati nel TargetDataSet (la nostra FDMemTable1).





Da qui in poi, possiamo lavorare con i nostri dati a disposizione e, per esempio usare i live bindings per costruire comodamente la nostra GUI (VCL o FireMonkey) o direttamente i componenti db-aware (VCL).



Ho registrato un video che mostra il componente all'opera, lo trovate qui:


Conclusioni

Probabilmente nelle prossime versioni di Delphi vedremo una sempre maggiore integrazione di FireDAC con l'ambiente di sviluppo e quindi può essere che questo approccio diventi obsoleto, ma per il momento mi sembra un modo comodo per costruire la GUI delle vostre applicazioni sfruttando le potenzialità RAD che fanno di Delphi (e RAD Studio) uno dei migliori ambienti di sviluppo in circolazione.

Sorgenti

Per chi non avesse confidenza con GitHub, qui c'è un link per scaricare un file zip.

Commenti e suggerimenti sono sempre ben accetti.
Buon lavoro,

Andrea

lunedì 10 novembre 2014

Disponibili i replay di CodeRage 9!

Nel canale Embarcadero di YouTube sono disponibili i replay delle sessioni di CodeRage 9 (conclusasi qualche giorno fa).
Molte di queste sessioni sono veramente interessanti e rappresentano ottimi esempi di uso delle ultime funzionalità di RAD Studio, spiegati dai migliori esperti internazionali.

Non posso che consigliarvi di dare un'occhiata (io ne ho una dozzina da guardare, avendole perse quasi tutte durante i giorni della conferenza) ! ;-)

Buona visione e buon lavoro

Andrea

giovedì 6 novembre 2014

Google Material Design e FireMonkey?

Google Material Design

Qualche settimana fa Google ha rilasciato ufficialmente le specifiche del Material Design, le nuove linee guida per la GUI delle applicazioni Android.
Si tratta di una documentazione molto estesa che riguarda moltissimi aspetti della GUI delle applicazioni mobile e sicuramente ci vorrà del tempo prima che tutte queste proposte vengano assorbite dagli sviluppatori di tutto il mondo.
Alcune applicazioni molto popolari però hanno già pubblicato degli aggiornamenti includendo elementi del Material Design e ovviamente non c'è miglior fonte di ispirazione delle applicazioni di Google stessa (Chrome, Google+, Play Store, Play Music, ...).

Da qualche giorno stavo cercando di mimare il comportamento dell'app Android Google+ per quanto riguarda le animazioni di entrata/uscita delle barre superiori e del pulsante delle azioni situato nella parte inferiore dello schermo.




Oltre a dare all'utente una sensazione di responsività dell'applicazione (c'è molta enfasi circa le transizioni animate nel Material Design), questo approccio permette anche di dedicare il massimo spazio disponibile alla lista dei contenuti che vogliamo presentare e al contempo poter usufruire di una barra del titolo di dimensioni decenti e che possa ospitare controlli anche complessi (ComboBox, Slider, trackbar ecc..).

Un tentativo

Con un po' di attenzione a non complicare troppo le cose, ho provato a replicare lo stesso effetto con Delphi XE7.
Ho scelto di usare una TListView come contenitore principale (popolandola con un TPrototypeBindSource) e l'ho posizionata sulla form (Align = Client).
Per poter aggiungere sopra di essa gli altri controlli interessati (le barre del titolo ed eventuali altri pannelli animati) senza interferire con la ListView stessa, ho aggiunto al suo interno un TLayout con Align = Contents (un valore introdotto nelle ultime versioni di Delphi che permette al layout di coprire l'intera area della listview), di modo da poter avere una sorta di secondo layer su cui poggiare altri componenti costituitivi delle barre superiori e della pulsantiera inferiore.


Sfruttando la proprietà ScrollViewPos della TListView (per capire come l'utente sta muovendo la lista), l'evento OnPaint della stessa (per avere una forte frequenza di aggiornamento, avendo cura di aggiungere qualche accorgimento per evitare di peggiorare troppo le prestazioni) e aggiungendo qualche effetto (TShadowEffect) qua e là, il risultato mi sembra abbastanza soddisfacente e si tratta in tutto di poche decine di righe di codice.
Ecco un paio di screenshot (che non rendono molto l'idea, trattandosi per lo più di animazioni) del risultato finale:


Si tratta ovviamente di un approccio minimale e per riuscire ad avere uno scostamento iniziale della listview tale da non far finire i primi item sotto i pannelli di intestazione, ho dovuto sacrificare la possibilità di sfruttare gli ItemHeader, forzandone uno di altezza pari ai pannelli di intestazione stessi (un po' un trucchetto, diciamo).

Vi invito a scaricare i sorgenti e provare direttamente (anche su Win32 ma meglio su un dispositivo mobile) o di installare direttamente l'APK di cui trovate il link qui sotto.

Update: ho aggiunto un video dimostrativo (grazie alla app gratuita Mirror)!

Source code e APK

martedì 4 novembre 2014

Delphi&Dintorni in Delphi Feeds (votate!)

Abbiamo aperto una richiesta per includere blog.delphiedintorni.it nei Delphi Feeds, un aggregatore di notizie nel mondo Delphi noto a moltissimi sviluppatori in tutto il mondo.
Se volete aiutarci, potete votare la richiesta al seguente indirizzo:


Grazie in anticipo!

Andrea