Interessante sessione seguita nel primo pomeriggio - al ritorno da una mattinata turistica nel centro di Barcellona - a proposito delle cose da non fare nelle applicazioni Silverlight. A parte alcuni consigli che non sempre possono essere seguiti (ad esempio sulla modalità WindowLess) molti altri tip sono sicuramente da considerare:

Install experience: E' utile modificare l'immagine di default (quella che chiede di installare Silverlight) per dare un'idea dell'applicazione cui l'utente sta accedendo. Una buona soluzione è quella di usare una immagine grayed che mostra l'interfaccia dell'applicazione cui si sta accedendo.

Load Experience: Minimizzare il tempo di caricamento. Il consiglio può sembrare ovvio ma naturalmente non è mai ripetuto troppo. Quindi per non mettere elementi eccessivamente pesanti all'interno di un XAP è opportuno usare

    • download on demand
    • cache nello isolated storage

Splash screen: L'uso di uno splash screen consente di migliorare la user experience e  di comunicare all'utente le informazioni di download. Esiste per questo una funzione javascript per tracciare il download.

Isolated Storage: la cache di dll, immagini, risorse, e altro nell'Isolated Storage oltre a consentire di dare migliori performance al download dell'applicazione può consentire di creare applicazioni che si avviano anche se si è offline.

Media: evitare di ridimensionare i video e i font. Questo perchè si tratta in entrambi i casi di operazioni molto onerose. Inutile dire che esistono casi in cui questo non è possibile, ma tenerlo presente è opportuno.

Processori multicore: Attenzione che Silverlight si avvantaggia molto dei processori multi-core. Tenetelo presente mentre sviluppate perchè poi non tutti i client avranno le stesse prestazioni della vostra macchina di sviluppo.

Design: Usare Dati di test per facilitare i designer. A questo scopo esistono due modi per individuare se si è a DesignTime:

    • DesignerProperties.GetIsInDesigneMode(this) - internamente ad UserControls
    • HtmlPage.IsEnabled - da altre classi

Debug settings: usare enableRedrewRegions = true per verificare quanto oneroso è il redraw dell'interfaccia. In questa modalità diagnostica il plugin lo renderà evidente con delle colorazioni particolari.

Elementi nascosti: Usare Visibility.Collapse invece che Opacity="0". Questo perchè gli elementi non vengono disegnati solo con l'attributo Visibility mentre con l'Opacity avviene lo stesso una valutazione dell'elemento una fase di rendering dello stesso.

Elementi di tipo Path: Non usare Width e Height con gli oggetti di tipo Path perchè è molto oneroso.

Memoria: usare GC.GetTotalMemory() per verificare il suo utilizzo.

Un'altro utile consiglio è stato quello di utilizzare il tool XPerf per monitorare iexplore.exe -> agcore.dll. Il tool è disponibile nel Windows Performance Tools Kit, v.4.1.1 (QFE)


Capita di rado, ma talvolta è necessario poter definire il binding di una proprietà da codice anzichè dal markup XAML. In questi casi tradurre la normale sintassi basata su una Markup Extension in codice vero e proprio non è immediato. Io stesso ho dovuto cercare un bel po’ prima di capire quali sono gli oggetti coinvolti e arrivare a tradurre i tutto in poche righe di codice C#.

Ma partiamo da un ipotetico Binding effettuato come di consueto da XAML:

   1: <TextBox x:Name="txtFirstName" Text="{Binding FirstName, Mode=TwoWay}" />

In questa singola riga è racchiuso e semplificato un po’ di codice. Innanzitutto la creazione di un oggetto che si occupa di fare il DataBinding e che incapsula le proprietà che abbiamo valorizzato, in questo caso Source e Mode, ma volendo anche alte come ad esempio il Converter e i suoi parametri. Infine l’assegnazione di questo oggetto alla proprietà che deve essere bindata.

Ecco in soldoni il codice che andrebbe scritto per simulare la Markup Extensione di cui sopra:

   1: // crea l'oggetto che contiene i parametri del binding
   2:  
   3: Binding binding = new Binding("FirstName")
   4: {
   5:     // sorgente del binding (DataContext)
   6:     Source = source,
   7:  
   8:     // modalità di binding
   9:     Mode = mode
  10: };
  11:  
  12: // assegno il binding alla textbox
  13:  
  14: element.SetBinding(TextBox.TextProperty, binding);

Questo non è molto codice, ma scriverlo ripetutamente magari su decine di proprietà è piuttosto laborioso e può aprire la strada a errori e omissioni. E allora perchè non scrivere un metodo che lo incapsuli. Anzi, visto che parliamo di usare il framework 3.5 la soluzione migliore è di scrivere un certo numero di Extension Methods che mettano a disposizione un po’ di overload per i casi più disparati:

   1: public static void Bind(
   2:     this FrameworkElement element, 
   3:     DependencyProperty property, 
   4:     string path, 
   5:     object source, 
   6:     BindingMode mode, 
   7:     IValueConverter converter, 
   8:     object converterParameter, 
   9:     CultureInfo converterCulture)
  10: {
  11:     Binding binding = new Binding(path)
  12:     {
  13:         Source = source,
  14:         Mode = mode
  15:     };
  16:  
  17:     if (converter != null)
  18:     {
  19:         binding.Converter = converter;
  20:         binding.ConverterCulture = converterCulture ?? CultureInfo.CurrentCulture;
  21:         binding.ConverterParameter = converterParameter;
  22:     }
  23:  
  24:     element.SetBinding(property, binding);
  25: }

In questo spezzone di codice viene mostrata la versione più ampia dei metodi in questione, cioè quella che accetta più parametri. Lascio a voi scegliere la combinazione di parametri che più vi aiuta. Se poi volete i miei vi segnalo che questa classe sarà disponibile nella prossima release della mia Silverlight Library 1.0. Ma vediamo come usare i metodi in questione dimostrando una versione con un po’ meno di parametri:

   1: txtFirstName.Bind(TextBox.TextProperty, "FirstName", source, BindingMode.TwoWay);

Questa riga effettua esattamente lo stesso binding dell’esempio scritto in XAML poco sopra. Siamo così riusciti nell’intento di semplificare il lavoro e di ridurre soprattutto la quantità di codice da scrivere.


E’ necessario che faccia questo post per una rettifica a proposito della sessione sugli ADO.NET Data Services che ho tenuto durante la serata dei Community After Hour. Si tratta tutto sommato di due piccolezze ma per completezza devo dare qui la versione corretta:

  1. Qualcuno mi ha fatto notare una inesattezza. Durante la sessione ho detto che per generare il proxy necessario per interrogare il servizio da Silverlight 2.0 è obbligatorio usare il tool da riga di comando datasvcutil.exe. In realtà se provate a referenziare il servizio con una Service Reference vedrete che Visual Studio 2008 è in grado di accorgersi che di DataService si tratta e di conseguenza generare il proxy corretto. Purtroppo seguendo svariati post in merito questa caratteristica non viene mai menzionata e io stupidamente non ci ho nemmeno provato.
  2. Alla fine della sessione mi è stato chiesto se è possibile fare uso del protocollo WS-Security con un ADO.NET Data Service. Di primo acchito trattandosi di un servizio esposto con WCF si può avere l’impressione che la cosa sia possibile. Ma soffermandosi un po’ a pensare mi sarebbe venuto in mente immediatamente che gli standard WS-* sono basati su SOAP e di conseguenza non è certo pensabile che funzionino con JSON e AtomPub. Quindi la risposta giusta è “no, non è possibile”. L’unica cosa da fare per proteggere il servizio è usare SSL.

Tutto qua. Non si tratta di questioni rilevanti, ma tutto sommato è meglio saperlo :)


Ormai ci siamo. Domani sera saremo tutti al Community After Hour di Padova (allo Sheraton) per condividere qualche ora sugli argomenti caldi del momento. Le slide sono pronte, il codice anche, e tutto sommato dovrebbe essere pronto anche lo speaker dato che pur uscendo da un periodo di superlavoro sono riuscito a ritagliarmi il giusto tempo per preparare la sessione.

Si parlerà di un argomento caldo: l'accesso ai dati da applicazioni RIA. L'argomento è molto sentito e non manca occasione perchè - oggi al messenger domani ad un evento - non mi senta rivolgere qualche domanda su questo "problema". Così la mia sessione sarà di carattere squisitamente pratico. Analizzeremo il problema dell'accesso ai dati così come è oggi e introdurremo una soluzione diversa che va nella direzione di risparmiare tempo sulle cose ripetitive che tipicamente sono la tomba della produttività.

Soprattuto vedremo come l'investire tempo nell'apprendimento di nuove tecnologie quali sono l'Entity Framework e gli ADO.NET Data Services possa pagare velocemente in termini di risparmio sul lavoro senza per questo dimenticare le buone norme di programmazione e architetturali.

Sarà una bella chiacchierata, che spero vi sia utile e che vi dia un impulso ulteriore - se ce n'è bisogno - nello sviluppo con Silverlight 2.0 e ASP.NET AJAX. E se la cosa vi piace vedremo di ripetere questa esperienza in qualche prossimo evento cercando di trovare sempre più il risvolto pratico e lasciare ad altri la mera enunciazione di nuove feature.

Qui i dettagli: http://www.microsoft.com/italy/eventi/days/community/xedotnet.mspx


Da un post di ieri ecco l'annuncio atteso da molti. Silverlight 2.0 RTW sarà rilasciato nella giornata di oggi. (considerato che il post è di ieri...)

I'm very pleased to confirm that we'll be releasing Silverlight 2 tomorrow.

http://silverlight.net/blogs/jesseliberty/archive/2008/10/13/silverlight-2-releases-tomorrow.aspx

Technorati Tags: ,,

Dopo il successo dello scorso 6 Marzo in questo mese ripeteremo la bella esperienza del Community After Hour. Il prossimo 23 Ottobre infatti troverete me e alcuni colleghi di XeDotNet al booth ATE dei Microsoft Days08 di Padova e alla sera potrete ascoltare le sessioni di , e di .

Qui trovate l'agenda della serata: http://www.microsoft.com/italy/eventi/days/community/xedotnet.mspx

L'argomento che affronterò durante la mia sessione sarà di sapore squisitamente pratico. Mi aspetto di avere poche slide, e una bella quantità di codice da vedere. L'accesso ai dati da applicazioni RIA è uno degli argomenti che mi viene richiesto spesso e volentieri, perciò ho deciso di mostrare un interessante connubio dato dall'Entity Framework e ADO.NET Data Services. Tramite essi saremo in grado di connetterci ad un database sia da Silverlight 2.0 che da AJAX. Si tratta di uno strumento efficace in questo contesto che consente di mantenere la suddivisione imposta da questo tipo di applicazioni che tipicamente non hanno accesso diretto alla base dati, ma nel contempo di evitare di scrivere decine di metodi di un webservice.

Vi aspetto numerosi. Passeremo assieme un'oretta decisamente proficua che potrebbe farvi cambiare l'approccio nella realizzazione di molte applicazioni.

Iscrizioni: http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032391659&Culture=it-IT


In queste ore sto lavorando alacremente alla preparazione del codice per il che si terrà a Padova il e mi sono scontrato con un problema che mi ha fatto perdere un po' di tempo.

In buona sostanza, mentre le query da Silverlight 2.0 verso un DataService (photoalbum.svc) sono andate lisce come l'olio una volta compreso il comportamento di Silverlight e del DataService, al momento di provare una "Insert"  mi sono scontrato con un solido muro. Ecco il codice che originariamente usavo nell'intento di aggiungere un Comment ad una classe Photo (il progettino di esempio è un semplice Album di foto):

   1: public static void SaveComment(Photo photo, string email, string text)
   2: {
   3:      PhotoAlbumEntities ctx = CreateContext();
   4:      Comment comment = Comment.CreateComment(0, email, text);
   5:      comment.Photo = photo;
   6:      ctx.AddToComment(comment);
   7:      ctx.MergeOption = MergeOption.AppendOnly;
   8:      ctx.BeginSaveChanges(OnCommentSaved, ctx);
   9: }

Dopo due nottate di indagini ed un consulto con il quale mi ha illuminato su come ottenere dei messaggi di errore comprensibili, è emerso che il codice qui riportato ha fondamentalmente due errori:

  1. Se provate ad eseguirlo e tracciate le chiamate HTTP vedrete che nella request non viene mai passato l'ID della Photo cui il commento è associato. Questo è in effetti un po' strano, ma pare che sia necessario fare uso di AddLink() per collegare esplicitamente un oggetto al proprio contenitore in questo modo:

    ctx.AddLink(photo, "Comments", comment);
  2. Purtroppo tutto ciò non basta, ed è stata proprio questa dualità che mi ha messo per un po' sulla strada sbagliata. Vi spiego quello che ho inteso dopo essermi un po' documentato: il fatto è che AddToComment() e AddLink() vengono trasformate in due chiamate sequenziali al DataServices in cui la prima aggiunge il commento nella propria tabella e la seconda crea il Link tra il commento e la foto. Ovviamente a leggerla così è lampante che non può funzionare. Non appena si aggiunge il commento questo fa fallire tutto perchè la relazione sul database impone che l'ID della foto sia specificato da subito. Ecco che alla fine ho scoperto che usando l'opzione "Batch" nelle opzioni di BeginSaveChanges()  il tutto comincia a funzionare perchè... le due chiamate vengono unite in una sola e quindi il DataService è in grado di fare le insert in modo corretto.

Ecco quindi il codice che effettua correttamente l'inserimento:

   1: public static void SaveComment(Photo photo, string email, string text)
   2: {
   3:     PhotoAlbumEntities ctx = CreateContext();
   4:     Comment comment = Comment.CreateComment(0, email.Text, text.Text);
   5:     comment.Photo = photo;
   6:     ctx.AttachTo("Photo", photo);
   7:     ctx.AddToComment(comment);
   8:     ctx.AddLink(photo, "Comments", comment);
   9:     ctx.MergeOption = MergeOption.AppendOnly;
  10:     ctx.BeginSaveChanges(SaveChangesOptions.Batch, OnCommentSaved, ctx);
  11: }

La chiamata al metodo AttachTo() in realtà è richiesta da AddLink() che si aspetta che gli oggetti che deve linkare siano tracciati dal contesto. Esso infatti ha proprio lo scopo di aggiungere un oggetto alla gestione del tracking.

Tutto questo può sembrare un po' laborioso, e anzi probabilmente lo è, ma rimane il fatto che gli ADO.NET Data Services in realtà sono davvero utili e fanno risparmiare un sacco di tempo.

tags: - categories: XAML

Ieri ho trovato qualche minuto da dedicare alla mia Silverlight Library. Ho pubblicato la nuova versione ricompilata per porter funzionare con la Release Candidate 0 di Silverlight 2.0. In realtà la libreria non ha subito sostanziali modifiche se non la rimozione di un paio di attributi TextAlignment nelle pagine di esempio che con il nuovo runtime non funzionavano.

Link: http://www.codeplex.com/silverlight


Un collega che sta lavorando molto con la Datagrid di Silverlight mi ha segnalato che nel passaggio dalla Beta2 alla RC0 è stato rimosso un evento dalla DataGrid e questa modifica non è segnalata tra le . L'evento in questione è il della DataGrid che dovrebbe servire ad intercettare l'istante in cui l'edit di una cella viene "committato" sulla sorgente dati. A mio parere questo evento si dovrebbe poter sostituire con la corretta gestione della sorgente dati e del Binding in modalità TwoWay, ma non ho ancora provato perciò non ne ho la certezza.

Rimane comunque il dubbio sul fatto che questa modifica importante (che al collega sta causando parecchi grattacapi) non sia stata segnalata nel documento suddetto. Forse non è considerata una breaking change?

tags: - categories: XAML

Il ContentPresenter di Silverlight 2.0 RC0 ha subito una importante modifica che ne ha causato la perdita di ben 18 proprietà. L'ottimo ha postato un articolo che spiega i motivi del cambiamento (che io ritengo più che legittimi) e come usare il nuovo controllo.

Link: RC0 & ContentPresenter

tags: - categories: XAML