La presentazione è in caricamento. Aspetta per favore

La presentazione è in caricamento. Aspetta per favore

Learn & Get Day #2: Sviluppo applicazioni.

Presentazioni simili


Presentazione sul tema: "Learn & Get Day #2: Sviluppo applicazioni."— Transcript della presentazione:

1 Learn & Get Day #2: Sviluppo applicazioni

2 Tipi di applicazioni (Windows)
Windows Forms ...le conosciamo tutti... .NET Class Library Libreria di classi (business layer) Console Application Applicazioni console GUI DOS Like Windows control library Libreria di controlli windows Window Service Applicazione windows che girano al termine del boot di Windows Altri template Estensioni di Visual Studio installate successivamente

3 Startup FormX Sub Main Application Framework
Può stare in una classe Application Framework Si decide dalle proprietà del progetto (MyProject) Impostazioni tipiche (Versione, Icona, Mode...) Public Sub Main() End Sub Public Sub Main(args() as String) End Sub Environment.GetCommandLineArgs() Environment.CommandLine()

4 Mostrare il form da Sub Main
Form è una classe in System.Windows.Form Come tale va trattata I forms sono classi che ereditano da Form Sono realizzati come classi parziali (.designer.vb) Non modificate il codice nel file .designer.vb Il dilemma Form1.Show() L’applicazione non parte... Application.Run L’applicazione ‘vive’ finchè ‘vive’ il form principale Usate Application Framework Analizzate la classe Application Application.ThreadException Application.Idle Application.DoEvents Application.Restart

5 Layout dei controlli Controllo dell’allineamento SnapLines
Margins (Bordo esterno) Padding (Bordo interno) Dock Anchor SplitPanel LayoutControls FlowLayout TableLayout Form Layout MaximumSize MinimumSize StartPosition FormBorderStyle

6 Form AutoScroll Opacity Shaped Styles TopMost DialogResult
I form possono essere trasparenti Shaped I forms possono avere forma irregolare Styles Application.EnableVisualStyles TopMost DialogResult CenterToParent, CenterToScreen Centrano il form rispetto al parent o allo schermo AcceptButton e CancelButton Interazione e aggiunta controlli Supportano controlli COM (ocx)

7 Menu,ToolBars, StatusBars e ToolTips
Permettono di creare UI stile Office 2003 Il look è basato su una classe ToolStripRenderer Draw Custom Renderer Professional Renderer ToolStripItem ToolStripContainer Permette di gestire il docking di items Il renderer gestisce Load e Save dello stato degli items ToolStripManager Persiste/recupera il layout (Load/SaveSettings) Stabilisce il renderer da usare ContextMenuStrip Permette di creare menu contestuali Tooltip component Help component

8 Applicazioni MDI Form.IsMDIContainer=True Form.MdiParent=Me
ToolStripMenu.MdiWindowListItem Indica quale item gestirà le finestre visualizzate Form.ActiveMDIChild Indica il chil form attivo Evento Form.MDIChildActivate Generato quando il child form si attiva LayoutMDI Modifica il layout delle finestre child

9 Eredità Visuale E’ possibile applicare l’ereditarietà anche ai Form
Creare form che ereditano UI e funzionalità da altri Si può quindi evitare di rigenerare lo stesso form tutte le volte

10 Dialogs & Validation Come in VB6 BrowseFolderDialog
Controlli che facilitano l’uso delle dialogs OpenFileDialog SaveFileDialog FontDialog ColorDialog ... Sono delle classi, quindi non è necessario usarli  BrowseFolderDialog Eventi Validating e Validated Permettono di validare il contenuto di un controllo Form.ValidateChildren ErrorProvider Fornisce indicazioni visive quando un controllo non è validato

11 Mouse & Keyboard Non ci sono grandi differenze
Ogni controllo ha una serie di eventi MouseEnter MouseLeave MouseHover MouseWheel (non visibile nella Property window) Control.SelectNextControl() Control.GetNextControl() KeyDown,KeyUp... e.Handled=True indica che il tasto è stato gestito e non deve essere propagato agli altri gestori evento Control.ModifierKeys Per conoscere lo stato dei tasti Ctrl,Shift e Alt

12 Drag & Drop L’operazione è manuale e sincrona
E’ iniziata dal metodo DoDragDrop Si applica ai controlli che hanno AllowDrop=True Espongono una serie di eventi DragEnter DragLeave DragOver DragDrop In DragEnter decidiamo quale operazione è applicabile Copy,Move,None In DragDrop Recuperiamo il dato GiveFeedback Permette di usare dei cursori custom (source) E’ possibile usare oggetti custom serializzabili

13 Printing VB6: Printer agiva esclusivamente sulla stampante
VB2005: PrintDocument System.Drawing.Printing Descrive il documento da stampare (titolo...) Fornisce una serie di eventi per il processo di stampa Print() -> PrintPage Non descrive il target della stampa Il Target è l’oggetto astratto PrintController StandardPrintController: Agisce sulla stampante (default) PrintPreviewController: Fornisce un anteprima della stampa Eventi BeginPrint PrintPage EndPrint QueryPageSettings Permette di cambiare i dettagli della pagina (margini, colore...)

14 Printing PageSetupDialog PrintDialog PrinterSetting Tricks
Impostazioni della pagina di stampa PrintDialog Selezione della stampante di destinazione E’ esposta dalla proprietà PrinterSettings di PrintDocument PrinterSetting Contiene tutte le info della stampante (IsDefault, Name...) InstalledPrinters Elenco delle stampanti installate Tricks PrintDoc.PrinterSettings.PrinterName=“...” Creare un custom PrintController per pagine dinamiche

15 Controlli Custom Scrollabe User Control Component OwnerDraw Inherited
Eredita da Control La renderizzazione è a carico dello sviluppatore Scrollabe Eredita da ScrollableControl Inherited Eredita da un altro controllo Permette di personalizzare un certo controllo User Control Eredita da UserControl “MiniForm” con micro-funzionalità Component Eredita da Component Non hanno interfaccia grafica, facilitano l’uso a design time OwnerDraw Controlli standard che delegano la gestione della UI al programmatore

16 Controlli -Ereditarietà
Object Component Control ScrollableControl UserControl

17 Controlli - Attributi Permettono di personalizzare l’integrazione del controllo nel designer. Description(“Routa il testo di 180°”) Category(“My Category”) Browsable(true) ReadOnly(true) DisplayName Indica il nome che apparirà nella Property Grid

18 Controlli - Attributi DesignOnly EditorBrowsable ToolboxBitmap
Determina se la proprietà è usata solo a design time EditorBrowsable Visibilità a livello intellisense ToolboxBitmap Icona associata al controllo DefaultEvent Evento di default DefaultProperty Proprietà di default DefaultValue Valore di default (usato per la serializzazione) Localizable Permette la localizzazione della proprietà ParenthesizePropertyName Visualizza la proprietà tra parentesi SettingsBindable Indica che la proprietà supporta binding MergableProperty Indica se la proprietà può essere “comunizzata” con altre DesignerSerializationVisibility Controlla la persistenza delle proprietà

19 Controlli - OwnerDraw Listbox, ListView, ComboBox...
Proprietà DrawMode Standard, OwnerDrawFixed,OwnerDrawVariable Evento MeasureItem Chiede quali sono le dimensioni dell’area da passare all’evento DrawItem Evento DrawItem Viene passato un oggetto Graphics rappresentante l’area su cui ‘agire’ e l’indice dell’item da disegnare

20 Risorse Vengono inserite nel manifest dell’assembly
Informazioni inserite nell’assembly a compile time che possono essere lette a runtime Vengono inserite nel manifest dell’assembly Identificate con Namespace.Nome.Estensione Assembly.GetManifestResourceNames Assembly.GetManifestResourceStream Le risorse non sono by default tipizzate VS usa un file .resX il quale wrappa e tipizza le risorse L’editing avviene attraverso l’editor di Visual Studio Le risorse possono essere embedded o linkate ResourceManager Permette di leggere il contenuto dei files .resX VS 2005 facilita l’utilizzo I files .resX hanno un apposito editor Genera una classe che espone le risorse in modo tipizzato I files .resX sono gestiti dai vari controlli presenti in VS

21 Localizzazione Globalizzazione Localizzazione
L’assicurare che un applicazione funzioni in qualsiasi parte del mondo senza dovere ricompilare l’applicazione Localizzazione La capacità di un applicazione di gestire la ‘cultura’ locale

22 Localizzazione in VB6 VB6 No local/region aware
Aggiunta di un file .res al progetto Utilizzo del resource editor Localizzare testo usando LoadResString LoadResPicture LoadResData No local/region aware Difficile integrare culture diverse Difficile estendere la localizzazione No locale adaptive UI No RTL support

23 Localizzazione in .NET .NET ResourceManager Tools
Si appoggia su files xml (.resx) ResGen.exe .resx -> .resources Le culture vengono gestite attraverso la classe CultureInfo ResourceManager Cerca le assembly satellite utilizzando la cultura della UI Probing <language-culture> <language> Neutral / Default culture Tools WinRes.exe Lutz Roeder’s Resourcer (http://www.aisto.com/roeder/dotnet/) Al.exe

24 Windows (Forms/controlli) Windows (Forms/controlli)
SubClassing Applicativo S.O Windows Messaggi Message pump Messaggi WndProc WndProc Windows (Forms/controlli) Windows (Forms/controlli)

25 SubClassing in VB6 VB6: SetWindowLong (GWL_WNDPROC )
Private Sub Form_Load() _OldWindowProc = SetWindowLong(Me.hwnd, GWL_WNDPROC, _ AddressOf NewWindowProc) End Sub Public Function NewWindowProc(ByVal hwnd As Long, ByVal msg As Long, ByVal wParam As Long, lParam As Any) As Long ... NewWindowProc = CallWindowProc( _ OldWindowProc, hwnd, msg, wParam, lParam) End Function Private Sub Form_Unload(Cancel As Integer) SetWindowLong _ hwnd, GWL_WNDPROC, _ OldWindowProc

26 SubClassing in VB6 Svantaggi Alternative IDE Molto fragile
Debug difficile Facile sbagliare Alternative MsgHook MsgBlaster

27 SubClassing in .NET La classe Control espone WndProc (protected)
Alla WndProc viene passata la struttura Message E’ possibile intercettare i messaggi, modificarli e/o passarli alla classe base IMessageFilter Permette di intercettare messaggi prima che vengano inviati a Form/Controllo Application.AddMessageFilter Application.RemoveMessageFilter

28 Asyncronous Programming
Esistono 3 tipi di timer System.Windows.Forms.Timer Il “classico” timer basato su WM_TIMER Tick ogni 55 ms System.Timers.Timer Basato su thread (evento) Usa SyncronizyingObject per sincronizzare l’evento Se il marshaling è occupato, accoda gli eventi System.Threading.Timer Basato su thread (callback) Più preciso BackgroundWorkerThread Semplifica l’asyncronous programming

29 PInvoke La porta ‘di servizio’ per accedere direttamente a codice unmanaged Win32 API Dll statiche (non COM) Codice .NET C#,VB.NET... PInvoke .NET Framework Win32 APIs

30 PInvoke – Attributo DllImport
System.Runtime.InteropServices .NET “way“ C# e VB.NET Enunciato Declare VB.NET Only Può stare ovunque (form,classe...) Qualche limitazione rispetto a <DllImport> APIViewer 2003 utility

31 PInvoke – Attributo DllImport
<DllImport("user32.dll”)> _ Shared Function GetWindowText _ (ByVal hWnd as IntPtr, ByVal lpString As StringBuilder, ByVal cch as Int32) as Int32 End Sub Named arguments Charset (Ansi,Auto e Unicode) Declare [Auto,Ansi e Unicode] Sub... ExactSpelling [true,false] EntryPoint Alias “...” CallingConvention[WinApi,CDecl...]

32 PInvoke – Attributo DllImport
SetLastError[true,false] True solo se usate Declare ... Memorizza il codice di errore Win32 generato dalla funzione GetLastError() e FormatMessage() APIs Permette di ottenere ulteriori informazioni sulla causa di errore di una chiamata ad una funzione Win32 Riduce le performaces Int32 err=Marshal.GetLastWin32Error() System.ComponentModel.Win32Exception()

33 PInvoke – Marshal di parametri numerici
BOOL Beep( DWORD dwFreq, DWORD dwDuration ); <DllImport("kernel32.dll")> _ Shared Function Beep(ByVal dwFreq As UInt32, _ ByVal dwDuration As UInt32) As Boolean End Function

34 PInvoke – Direzione dei parametri
I parametri hanno una direzione [in] ByVal (VB.NET) [out] ByRef (VB.NET) [in,out] ByRef (VB.NET) BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped ); <DllImport("kernel32.dll", SetlastError:=True)> _ Private Shared Function WriteFile(ByVal hFile As IntPtr,_ ByVal Buffer As Byte(), ByVal nNumberOfBytesToWrite As Integer, _ ByRef lpNumberOfBytesWritten As Integer, _ ByRef lpOverlapped As OVERLAPPED) As Integer End Function

35 PInvoke – Marshaling di stringhe
Direzione [in] ByVal ... As String [out] ByVal ... As System.Text.StringBuilder Le Win32 API non ritornano mai stringhe In .NET le stringhe sono immutabili BOOL GetUserName( LPTSTR lpBuffer, LPDWORD nSize ); <DllImport("Advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _ Public Shared Function GetUserName(ByVal buffer As StringBuilder, ByRef bufferLen As Integer) As Boolean End Function

36 PInvoke – Marshaling di strutture
ByVal [in] o ByRef [in/out] Il layout della struttura deve essere rispettato Il compilatore può inserire dei byte di padding Structure Test Dim P1 as Byte // 1 byte Dim P2 as Int32 // 4 bytes Dim P3 as Int32 //4 bytes End Structure Marshal.SizeOf( Test.GetType) // ? [StructLayout(LayoutKind.Sequential,Pack=1)] Structure Test Dim P1 as Byte // 1 byte Dim P2 as Int32 // 4 bytes Dim P3 as Int32 //4 bytes End Structure Marshal.SizeOf( Test.GetType) // 9 [MarshalAs(UnmanagedType.LPStr,SizeConst=128)] param As String

37 PInvoke - Callbacks #1 #2 #3 Uso!
BOOL EnumWindows(WNDENUMPROC lpEnumFunc,LPARAM lParam ); BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam ); Delegate Function EnumCallback _ (ByVal hWnd As IntPtr,ByVal param As Int32) As Boolean #1 #2 <DllImport("user32.dll")> Shared Function EnumWindows _ (ByVal callBack As EnumCallback,ByVal param As Int32) As Boolean Private Function MyCallback (ByVal hWnd As IntPtr, ByVal param As Int32) As Boolean Return True End Function #3 Uso! EnumWindows(New EnumCallback(AddressOf MyCallback), 1234)

38 Common Language Runtime Runtime Callable Wrapper
Interoperabilità COM .NET può usare oggetti COM TlbImp (nell‘ SDK) Strong named, modificare il namespace esportato Impostando un reference ad un assembly COM Marshal.ReleaseCOMObject RegFreeCOM Usare Assembly COM senza registrarle IFoo IUnknown ComServer Common Language Runtime Object Runtime Callable Wrapper Client Reference Counted

39 Common Language Runtime
Interoperabilità COM .NET può creare oggetti COM Il framework è sempre necessario Add – New Item – COM Class Usando <ComVisible> è possibile decidere cosa esporre al mondo COM Register For COM Interop RegAsm RegSvr32 per assembly .NET Creaun file .reg con le info di registrazion TlbExp Esporta la type library (early binding) da un assembly .NET Com enabled Common Language Runtime COM Client IFoo IDispatch IUnknown COM Callable Wrapper Server Client

40 ADO.NET Motore di accesso ai dati unificato per le applicazioni .NET
Windows, Web, Mobile apps Nato per superare i limiti di ADO (COM,XML Support, Evolution approach) Wrapper attorno al motore OLE DB ADO.NET No usa OleDB/COM ma providers nativi .NET Non supporta cursori lato server Consumano risorse lato server e non applicabili in alcuni tipi di applicazioni Supporta firehose cursors (read only, fwd only) Supporta resultsets disconnessi Ampio supporto all’ XML Doppia modalità di funzionamento Connesso Connesso alla fonte usando firehose cursor Disconnesso Leggo i dati in un dataset e sconnetto (optimistic batch update mode)

41 ADO.NET – Oggetti principali
Connection E’ l’oggetto che permette la connessione al DB ConnectionString (compatibile con VB6) Open/Close Command Indica il comando (Select,Update...) da inviare DataReader Permette la lettura dei dati eventualmente ritornati dal comando DataAdapter Esegue il command e ritorna un DataSet / DataTable Effettua la riconciliazione dei dati nel DB

42 ADO.NET – Oggetti principali
DataTable Nuova versione del ResultSet Disconnessa e Client Side DataSet Contiene più DataTable Posso definire delle relazioni tra DataTable Database, in memory e disconnesso Totalmente indipendente dalla fonte dati Text files, Xml files, DataBase...

43 ADO.NET – Providers Blocchi di connessione all’ engine DB
OLEDb Provider Permette di accedere a DB per i quali esiste un provider OLE DB MDac (ultima) + Jet Engine SQLProvider SQLServer 7.0 e superiore No MDac Provider nativo e ottimizzato per SQLServer Offre funzionalità aggiuntive disponibili in SQLServer

44 ADO.NET – Namespaces Tutte le classi sono in System.Data
System.Data.OleDB Contiene tutte le classi per il provider OLEDB System.Data.SQLClient Contiene le classi native per SQLServer System.Data.Common Contiene le classi independenti dal provider (DataSet) ProviderFactory E’ il provider che si occupa di creare l’oggetto corretto

45 ADO.NET – Connection E’ l’oggetto che effettua la connessione al DB
ConnectionString www. Connectionstring.com Provider=Microsoft.Jet.OLEDB4.0 (no per SQLConnection) Initial Catalog / DataSource= /AttachDBFilename= Open, Close, State In caso di problemi viene generata una OLEDB/SQLException Ha una collezione Errors che fornisce dettagli sul problema Connection Pooling Quando ci si connette ad un DB il provider crea un pool di connessioni simili affichè ulteriori richieste di connessioni vengano gestite velocemente Basato sulla ConnectionString,può essere disabilitato,ConnectionTimeout BeginTrans OggettoTransaction su cui eseguire Commit o RollBack IsolationLevel determina la modalità di lock durante la transazione

46 ADO.NET – Command E’ l’oggetto che specifica quale azione compiere verso il DB CommandText La query SQL da eseguire CommandType Text, StoreProcedure Connection Connessione associata Parameters Collezione di parametri associati alla query (da preferire) ExecuteReader Ritorna un DataReader per l’accesso ai dati della query ExecuteScalar Esegue query e ritorna il valore della prima riga/colonna Select Count(*) FROM ... ExecuteNonQuery Esegue la query e ritorna il numero di righe modificate UPDATE SET...

47 ADO.NET – DataReader Cursore ForwardOnly e ReadOnly Command Connection
Permette di leggere i dati ritornati dalla query Command Comando associato Connection Connessione associata HasRows Indica la presenza di righe da leggere nel DataReader Read Legge il record successivo, ritorna false al termine GetSchemaTable Ritorna una DataTable con lo schema del DataReader Close Chiude il DataReader e rilascia le risorse associate While reader.Read() Data=Reader(columnIndex) ... Data=reader(“FirstName”) End While

48 ADO.NET – DataTable Recordset statico disconnesso In memory table
Formata da DataColumns e DataRows Può contenere dati provenienti da più fonti (Query, file XML, codice...) Database independent PrimaryKey (colonne che compongono la primarykey per quella tabella) DefaultView permette il filtering e sorting dei dati contenuti Rows Collezione delle “righe” contenute nella tabella NewRow: Crea una nuova riga Delete: Marca la riga come deleted Ogni row mantiene il proprio stato e valore E’ spesso contenuta in un DataSet AcceptChanges / RejectChanges Resetta lo stato delle righe nella DataTable

49 ADO.NET – DataSet DataRelations Constraints XML Support
In memory disconnected database Permette una visione gerarchica dei dati Contiene 1 o più tabelle – Tables property DataRelations Descrive la relazione tra tabelle Permettono di navigare tra le relazioni ChildRelations ParentRelations Constraints Regole di validazione dei dati presenti nel DataSet Column Level: DataColumn (Unique, MaxLength...) Table Level: ForeignKeyConstraint Autogenerati in base alle relazioni tra tabelle DeleteRule, UpdateRule XML Support Lo schema e i dati possono essere memorizzati in un file XML

50 ADO.NET – DataSet Constraint Columns Column DataSet Tables Table
Constraints Constraint Columns Column DataSet Tables Table Oggetto Collezione Relations Relation Rows Row

51 ADO.NET – DataView E’ una “vista” dei dati contenuti in una tabella
Permette di avere delle viste ordinate e filtrate Composta da insieme di DataRowView Permette inserimenti/Eliminazioni Agisce sulla Datatable associata Usato nel DataBinding Dim dv as New DataView(EmpTable) dv.RowFilter=“FirstName LIKE A%” dv.Sort=“FirstName,LastName” dv.RowStateFilter=DataViewRowState.Unchanged

52 ADO.NET – DataAdapter E’ l’anello di congiunzione tra DB e DataSet
E’ provider dependent Commands SelectCommand InsertCommand DeleteCommand UpdateCommand Fill Riempe un DataSet con le info prese dal DB FillSchema Crea lo schema da un DB Update Allinea il DB con il contenuto del DataSet

53 ADO.NET – Update Model Optimistic batch Update
Possono esserci conflitti First / Last Win Il comando Update scorre le righe e in base allo stato invoca il comando SQL parametrico nei vari Cmds I comandi possono essere autogenerati CommandBuilder Esegue una Select per recuperare le info Single Table, Primary Key, PK nella query, No SP Ogni DataTable ha un DataAdapter associato HasChanges e GetChanges Ritorna un DataSet con le sole modifiche I parametri dei comandi indicano Da quale colonna della DataRow recuperare il dato Quale versione del dato usare (Current o Original) Eventi DataAdapter.RowUpdating e RowUpdated

54 DataBinding E’ “l’arte” di visualizzare dati ed aggiornarli
Classe Binding Gestisce il legame tra dato e user interface Espone eventi Format, Parse e BindingComplete Gestione update e null values Simple Binding Un singolo oggetto è la fonte di Binding Complex Binding Un insieme di oggetti è la fonte di binding (IList) Binding Manager Viene creato per ogni Data Source esposta a binding PropertyManager (fonte dati = single item) CurrencyManager (fonte dati = list) permette la navigazione Esposto da BindingContext (DataSource)

55 DataBinding INotifyPropertyChanged IBindingList BindingList (Of T)
Informa il meccanismo di binding che una proprietà è cambiata IBindingList Gestisce i dettagli (AddNew,AllowNew...) per il complex binding Complessa da implementare BindingList (Of T) E’ un implementazione generica di IBindingList Fornisce il supporto al meccanismo di binding (Add,Update...) Non funziona con insiemi già esistenti (es: DataRows) BindingSource Rappresenta un fonte di Binding Si interpone tra la UI e la vera fonte dati Espone qualsiasi tipo come IBindingList Semplifica la gestione del Databinding DataSource accetta un Type e supporta Design mode

56 DataBinding – UI support
Data Sources Window Contiene le fonti di Binding Posso trascinare in un form una data source (Details/View) Lookup Data Disponibile anche per la DataGridView BindingSource support Sorting,Filtering e Searching

57 ClickOnce - Introduzione
Applicazioni “Rich Client” UI pratica e reattiva Difficili da distribuire e aggiornare Web Server centrale, fix once. Più difficile scrivere le applicazioni DHTML, Javascript No Offline mode UI Experience limitata Drag &Drop, Undo, Help...

58 ClickOnce - Introduzione
Oggi c’è sempre più richiesta di applicazioni con UI “ricche” Applicazioni Windows “Smart” Offrono tutti i vantaggi di un applicazione Win32 Hanno la capacità di auto aggionarsi Caratteristiche Hanno la capacità di interagire con l’hardware e il software installato Funzionano sia Online che OffLine Utilizzano una nuova modalità di deployment/update Possono funzionare su diverse piattaforme

59 ClickOnce - Caratteristiche
Supporta il deploy e update di applicazioni .NET CD-Rom Percorso di rete FTP WEB Integrata in Visual Studio 2005 Debug e Intellisense in Zone Permission richieste Permission calculator Deploy Online e Offline Update allo startup o programmatico System.Deployment RegFree COM

60 Slides?


Scaricare ppt "Learn & Get Day #2: Sviluppo applicazioni."

Presentazioni simili


Annunci Google