Technology Experience

.NET World

Programmazione, libri, snippet di codice, articoli tecnici

.NET World

Un ContextMenu un po’ più divertente

Ho lavoricchiato stasera ad un ContextMenu un pochino diverso da quello tradizionale, che visualizza un pallino colorato di fianco ad ogni voce e soprattutto contiene una StatusBar che cambia il suo contenuto in base alla voce del ContextMenu su cui ci troviamo con il mouse. Ho uploadato sul mio sito un piccolo zip che per adesso non rendo disponibile, così lo sistemo un po’: se ho tempo (ma non credo) ne parlerò velocemente domani.

Il succo sta nel fatto che la proprietà Header del MenuItem non è detto che debba contenere per forza solo del testo, anzi. Io ci ho infilato uno StackPanel con alcuni child al suo interno: un Ellipse ed una TextBlock per il testo vero e proprio. La cosa divertente è che ho creato uno UserControl per evitare di avere codice troppo prolisso nello XAML della Window. Ripeto: detto così in forma scritta non ha alcun senso, domani bloggo qualcosa perchè secondo me può essere utile.

Technorati Tags:  

Send to Kindle
.NET World

Risorse su WPF

Ho aggiunto tra i miei feed preferiti e che leggo tutti i giorni quello di un certo Jaime Rodriguez che sembra essere tosto sul fronte WPF. Mi è piaciuta la mini-serie di 3 post sul drag’n’drop con WPF, perchè è molto chiara e non è per nulla complessa, anzi. Sottoscrivetevi al suo blog qua.

I tre post che parlano di drag’n’ su WPF sono questi:

Drag & Drop in WPF … Explained end to end ..

Drag & drop in WPF part2 …

Drag & Drop in WPF.. part 3 .. the results and code…

Technorati Tags:   

Send to Kindle
.NET World

Scambio di e-mail con Petzold

Ho scritto a Charles Petzold qualche volta in passato, parlando del suo libro e di WPF. Come ho avuto modo di dire in passato, non è che il suo Application + Markup mi abbia entusiasmato moltissimo. Ma Petzold sa come tenersi stretti i suoi lettori: a chiunque abbia un blog in cui si parli di Presentation Foundation, promettere di regalare una copia del suo prossimo libro 3D Programming for Windows, in uscita il prossimo 25 Luglio. Vabbè che su WPF ce ne saranno di migliori, ma come lui stesso ha detto a me: “My WPF 3D book is coming out in a couple weeks and I think every WPF blogger should get a copy.“.

Beh, che dire…Thanks Charles!

Technorati Tags:   

Send to Kindle
.NET World

Windows SDK: wpfperf e l’irrimediabile crash

ll titolo fa anche (quasi) rima…non è proprio rima…come si dice? Assonanza? Giusto
Torniamo a noi, perchè sono stanco.

Questa sera ho voluto dare un’occhiata al Performance Profiling Tools for Windows Presentation Foundation incluso nel Windows SDK. Si tratta di uno strumento che serve a capire come l’engine di WF spende il suo tempo nelle varie fasi di rendering, layouting (!), gestione degli handler e così via. Causa ingenti impegni sul lavoro, ho solo letto velocemente qualche interessante articolo su MSDN e mi sono messo questa sera a sperimentarlo un pochino.

Ho trovato inizialmente qualche difficoltà, perchè il tool tende a crashare un po’ troppo spesso, se non viene maneggiato con cura. Innanzitutto, per lanciarlo è sufficiente aprire il command prompt del Windows SDK e lanciare da riga di comando wpfperf. La prima cosa che wpfperf ci propone è l’aggiunta di qualche assembly. Da buon ignorante, pensavo di dover puntare il folder della mia applicazione, mentre in realtà non è proprio così. Dunque, procediamo con calma: al primo avvio wpfperf ci propone questa dialog:

Questi sono assembly che wpfperf può utilizzare per profilare la nostra applicazione. La ListBox nella parte inferiore è a selezione multipla, quindi, per esempio, possiamo selezionare il Visual Profiler, l’Event Trace ed il Trace Viewer ed attivarli. Non so bene per quale motivo wpfperf ci chieda queste informazioni: penso che questo tool offra qualche spunto di estensibilità, tale per cui uno sviluppatore possa creare un nuovo assembly per creare propri strumenti di profiling dedicati a WPF.

Se selezioniamo il Visual Profiler, quello che mi è sembrato più interessante, dopo averlo selezionato dalla dialog qui sopra dobbiamo cliccare sul pulsante Start Profiling. Appare un’altra finestra che ci elenca tutte le applicazioni correntemente attive che utilizzano WPF: mentre vi sto scrivendo sto utilizzando Windows Live Writer, e proprio questo software appare in questo elenco. Se volessimo profilarlo, non dobbiamo fare altro che selezionarlo dalla ListBox e cliccare su Ok. Ci ho provato, ma wpfperf crasha irrimediabilmente. E non crasha solo con Windows Live Writer, ma con qualsiasi altra applicazione WPF, tipo il mio Flickr Browser ed altre cose.

Di primo acchito quindi wpfperf non funziona proprio.

Ma non mi sono arreso. Il crash di wpfperf fa riferimento ad un’eccezione FileNotFoundException. Mi sono incuriosito ancora di più, ed in giro sul Web ci sono diversi post sui forum MSDN dove si spiega come risolvere questo problema. Il file che wpfperf cerca e non trova si chiama WpfPerformanceDiagnostics.dll e si trova nella directory bin del Windows SDK (di default è C:Program FilesMicrosoft SDKsWindowsv6.0Bin). Questo assembly va bene lì dov’è, ma non basta: va copiato anche nella stessa directory dove si trova l’assembly che vogliamo profilare. Per evitare che il Visual Profiler di wpfperf crashi inesorabilmente ogni volta che tentiamo di usarlo, quindi, dobbiamo copiare a mano questo assembly nelle varie directory che ci interessano.

Fatto questo, possiamo usare wpfperf per vedere quanto tempo impiega WPF a renderizzare le nostre applicazioni, quanto tempo ci mette a calcolare il layout dei controlli inseriti nei vari panel, quanto tempo passa ad esaminare l’input da tastiera e da mouse, etc. etc. Adesso che funziona, vorrei davvero studiarmelo un pochino.

Mi ero ripromesso di essere rapido, ma anche questa volta non ce l’ho fatta. I’m sorry.

Technorati Tags:

Send to Kindle
.NET World

Security Lifecycle Development

Qualche notte fa facevo fatica a dormire…vuoi per il caldo, vuoi per chissà cosa…ho tirato fuori il mio Security Lifecycle Development e ho dato un bel botto in avanti alla sua lettura. Mi sono imbattuto – da buon ignorante – nell’acronimo STRIDE che mi ha fatto ridere almeno quanto la prima volta che ho sentito citare CRUD.

STRIDE è un acronimo le cui iniziali stanno per Spoofing, Tampering, Repudiation, Information disclosure, Deniaf of service ed Elevation of privilege. Nel libro vengono solamente citate nei loro concetti essenziali, ma son convinto che si potrebbero scrivere centinaia e centinaia di pagine su ciascuna delle minacce di sicurezza elencate prima.

Questo articolo su MSDN Magazine del Novembre 2006 riprende tutti questi concetti. Avevo già l’abbonamento a MSDN Magazine in quel periodo, ma evidentemente devo aver accantonato l’articolo pensando che non servisse nel mio lavoro. Ma la lettura di Security Development Lifecycle mi sta facendo davvero ricredere.

Technorati Tags:   

Send to Kindle
.NET World

Usare la ListView

Partiamo da questo screenshot:

L’altra volta avevamo visto come gestire da codice l’orribile TextBox inserita nel menù, con il relativo Button per poter salvare l’immagine sul proprio disco fisso locale. Per maggiori informazioni leggete questo post.

Questo ContextMenu dà accesso ad alcune altre funzionalità piuttosto divertenti, come quella per richiedere l’elenco dei tag associati ad una particolare fotografia. Il codice è molto semplice e compatto:

private void TagsMenuClick(object sender, RoutedEventArgs args) { FlickrBrowserPhoto photo = lstPhotos.SelectedItem as FlickrBrowserPhoto; string id = photo.PhotoId; PhotoInfoTag[] tags = flickrConn.PhotosGetInfo(id).Tags.TagCollection; StringBuilder bld = new StringBuilder(); foreach (PhotoInfoTag t in tags) bld.AppendLine(t.TagText); MessageBox.Show(bld.ToString()); }

Per semplicità, i tag vengono visualizzati con una rozza MessageBox.Show.

Quello di cui voglio brevemente parlare adesso è la visualizzazione delle informazioni EXIF associate ad una fotografia. Per farlo, ho creato una nuova Window, ExifWindow, il cui XAML è questo:

<Window x:Class="FlickrBrowser.ExifWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="FlickrBrowser" Height="300" Width="300" WindowStartupLocation="CenterScreen" > <ListView ItemsSource="{Binding Path=ExifTag}" HorizontalAlignment="Stretch" Margin="4" Name="lstExifInfo"> <ListView.View> <GridView> <GridViewColumn Width="100" Header="Label" DisplayMemberBinding = "{Binding Path=Label}" /> <GridViewColumn Width="100" Header="Value" DisplayMemberBinding = "{Binding Path=Raw}" /> </GridView> </ListView.View> </ListView> </Window>

Una Window, di dimensioni 300×300, che appare al centro dello schermo. Tale Window contiene un solo oggetto ListView, al quale diciamo che ogni item sarà di tipo ExifTag. La ListView comprende due colonne: la prima viene bindata alla proprietà Label della classe ExifTag, mentre la seconda alla proprietà Raw. Ho dato una larghezza alle colonne ed un header. Nulla di particolarmente complicato, insomma.

Quando l’utente vuole vedere le informazioni EXIF di una foto, utilizzo la libreria di Flickr per poter ottenere una struttura ExifTag[] da poter bindare.

private void ExifMenuClick(object sender, RoutedEventArgs args) { FlickrBrowserPhoto photo = lstPhotos.SelectedItem as FlickrBrowserPhoto; string id = photo.PhotoId; ExifTag[] exif = flickrConn.PhotosGetExif(id).ExifTagCollection; ExifWindow wnd = new ExifWindow(); wnd.SetExifInfo(exif); wnd.ShowDialog(); }

Ottengo il PhotoId della foto selezionata, ottengo l’elenco ExifTag[], creo un’istanza della Window ExifWindow, chiamo il suo metodo SetExifInfo e poi la visualizzo come modale. Quest’ultimo metodo pubblico è molto semplice:

public void SetExifInfo(ExifTag[] exif) { lstExifInfo.ItemsSource = exif; }

Non faccio altro che impostare il data-binding sulla ListView, dicendo di prendere l’elenco delle informazioni EXIF prelevate dalla foto. Il risultato è il seguente:

Ed il gioco è fatto!

Technorati Tags:    

Send to Kindle
.NET World

Template per evidenziare il SelectedItem di una ListBox

Alla fine della sessione di Corrado agli ultimi Community Days sul data-binding di WPF, gli ho chiesto se fosse possibile cambiare (e se sì, come) il template che WPF utilizza per evidenziare l’Item corrente su una ListBox. Il template di default è il classico blu, come quello che si vede nello screenshot qui sotto:

A volte potrebbe essere utile e carino definire un nostro template con cui far vedere all’utente quale degli elementi elencati nella ListBox è quello selezionato. Corrado mi parlò di una cosa…che adesso ovviamente non mi viene in mente… Ma ricordo anche che consigliò di sottoscrivere il blog www.beacosta.com che lui stesso definì come una risorsa piuttosto importante per tutto quello che riguarda WPF. Manco a farlo apposta, il post del 1° Aprile scorso parla proprio di questa cosa.

Non voglio fare banalmente il copia & incolla dello XAML che compare nel post, per questo basta che cliccate sul link qui sopra, cercate un attimo l’ultimo snippet di codice ed il gioco è fatto. Voglio farvi vedere quello che ho realizzato io partendo dagli spunti e dalle considerazioni che ho trovato nel post.

La logica riguarda principalmente il trigger, che scatta nel momento in cui la proprietà IsSelected del singolo ListBoxItem diventa true. Quando questa condizione è verificata, vengono eseguiti uno o più setter su una o più proprietà. Nel caso dell’esempio di prima l’ellisse serve ad evidenziare un pianeta, mentre nel mio caso vorrei fare qualcosa di diverso, ovvero cambiare semplicemente il colore di sfondo. Il blocco XAML è riportato qui sotto:

 

<Style TargetType="ListBoxItem"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListBoxItem}"> <Grid> <Rectangle x:Name="selectedItem" Margin="-10" StrokeThickness="2" Height="{TemplateBinding Height}" Width="{TemplateBinding Width}" /> <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsSelected" Value="true"> <Setter Property="Stroke" TargetName="selectedItem" Value="LightGreen"/> <Setter Property="Fill" TargetName="selectedItem"> <Setter.Value> <LinearGradientBrush StartPoint="0,0.1" EndPoint="1,0.1"> <GradientStop Color="LightGreen" Offset="0.0" /> <GradientStop Color="White" Offset="1.0" /> </LinearGradientBrush> </Setter.Value> </Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>

 

Il template è composto da una Grid, che contiene una sola colonna ed una sola riga…di conseguenza…una sola cella. In questa cella sono presenti due elementi: un Rectangle ed un ContentPresenter. Quest’ultimo è l’area che contiene il contenuto effettivo del ListBoxItem. Il rettangolo invece non ha bordo e soprattutto non è riempito: in altre parole, inizialmente non è visibile e l’utente proprio non lo vede.

Quando viene selezionato un ListBoxItem dalla ListBox, si scatena il trigger che non fa altro che settare lo Stroke del rettangolo a LightGreen, e settare il Fill con un effetto gradiente dal LightGreen al White. Il rettangolo copre completamente tutta l’area necessaria a contenere il ListBoxItem. L’effetto finale, al contrario di quello che dice Roberto (Rob, sto scherzando…sono d’accordo con te!), questa volta è davvero molto gradevole!

Insomma, adesso quando seleziono un elemento dalla ListBox non compare in uno stupido blu sempre uguale…e soprattutto ho imparato come usare un template custom, che vuol dire poter utilizzare immagini e stili per fare il tutto molto più gradevole. ‘Sto WPF, se non si fosse capito, mi intrippa proprio.

Technorati Tags:    

Send to Kindle
.NET World

WPF: gestire un ContextMenu con una TextBox interna

Guardate questo screenshot:

E’ lo screenshot di FlickrBrowser, il software in WPF che mi sto divertendo a creare nel tempo libero. Nella figura qui sopra, c’è l’elenco di 4 set fotografici: Microsoft Security Workshop VII, Giornata Azzurra 2007, AvioExpo 2007 e Nove Colli (Fiat 500) – 2007 – Fabio Edition. Il secondo set fotografico è selezionato: se ci facciamo sopra doppio-click, otteniamo la figura qui sotto:

In pratica, una ListBox orizzontale che visualizza tutte le foto associate al set fotografico che abbiamo selezionato. Ho associato un ContextMenu ad ogni Image, che ovviamente appare cliccando col pulsante destro del mouse. Il ContextMenu è stato inserito fra le risorse della Window; vi riporto lo XAML qui sotto.

<Window.Resources> <ContextMenu Name="mnuPhotoContextMenu" x:Key="menu" Opened="ContextMenuOpened"> <ContextMenu.Background> <LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> <GradientStop Color="Yellow" Offset="0.0" /> <GradientStop Color="White" Offset="1.0" /> </LinearGradientBrush> </ContextMenu.Background> <MenuItem Header="Tags" Click="TagsMenuClick" /> <MenuItem Header="Save As" Name="mnuSaveAs"> <StackPanel Orientation="Horizontal"> <TextBlock Text="Path :" /> <TextBox Width="100" Name="txtPath" Text="E:" HorizontalAlignment="Stretch" /> <Button Name="btnDownloadPhoto" Content="Ok" Click="btnDownloadPhotoClick" /> </StackPanel> </MenuItem> <MenuItem Header="EXIF Information" Click="ExifMenuClick" /> <Separator /> <MenuItem Header="Properties" /> </ContextMenu> </Window.Resources>

Al ContextMenu è stato associato un event-handler sull’evento Opened. Il Background del ContextMenu è un semplice gradiente, visibile nello screenshot. Ci sono diversi MenuItem: uno mostra i tag associati alla foto cliccata, un altro permette il Save As (ne parliamo adesso), un altro ancora mostra le informazioni EXIF della foto. L’ultimo, quello associato a Properties, non fa assolutamente un bel nulla.

Parliamo un po’ del Save As che è il più interessante.
Questo MenuItem contiene uno StackPanel con una TextBox ed un Button a fianco. L’utente può digitare un qualsiasi path nella casella di testo e poi cliccare sul Button per salvare l’immagine sul proprio disco locale. Ogni foto ha il proprio PhotoID, perciò ho voluto intercettare l’apertura del ContextMenu per dare un valore predefinito alla TextBox. Vediamo cosa fa l’event-handler dell’evento Opened del ContextMenu:

void ContextMenuOpened(object sender, RoutedEventArgs e) { if (lstPhotos.SelectedItem != null) { FlickrBrowserPhoto photo = lstPhotos.SelectedItem as FlickrBrowserPhoto; // Ottengo il riferimento alla TextBox che contiene il path ContextMenu menu = this.FindResource("menu") as ContextMenu; StackPanel p = ((MenuItem)menu.Items[1]).Items[0] as StackPanel; directoryTextBox = p.Children[1] as TextBox; directoryTextBox.Text = string.Format(@"E:{0}.jpg", photo.PhotoId); } }

Ottengo un riferimento al ContextMenu, poi “navigo” il visual-tree per raggiungere l’istanza prima dello StackPanel e poi della TextBox. Fatto questo, è sufficiente valorizzare la proprietà Text ed il gioco è fatto. Ovviamente il drive E: andrebbe messo a posto. Il click su Ok scarica la foto sfruttando la connessione attiva di Flickr.

La cosa brutta di questo sistema è che se cambiassi la struttura del ContextMenu, cambierebbe di conseguenza il visual-tree e quiandi bisognerebbe modificare la parte di codice che recuperare l’istanza. Lo StackPanel potrebbe non trovarsi più in menu.Items[1].Items[0]. E la TextBox un giorno potrebbe non essere più il Children[1]  dello StackPanel.

Technorati Tags:  

Send to Kindle
.NET World

Classi statiche & generics: un comportamento da tener presente!

Date un’occhiata alla seguente classica statica:

1 public static class DataProvider<T> where T : new() 2 { 3 private static bool init; 4 5 static void initialize() 6 { 7 init = true; 8 } 9 10 public static void MakeSomeOperation() 11 { 12 if (!init) initialize(); 13 } 14 }

Estratto da un data provider che ho sviluppato tempo fa.
E’ una classe statica DataProvider che fa uso di un generics <T>. Ha una proprietà statica booleana Init, che utilizza un field privato init. L’unico metodo presente è MakeSomeOperation(), statico anch’esso, che prima di fare qualcosa controlla se la classe è già stata inizializzata. Nulla di strano, giusto?

La morale però è questa: la prima volta che utilizzo questa classe chiamando il metodo pubblico MakeSomeOperation(), entro nel piccolo blocco if e quindi viene eseguita la initialize() privata. Poi init viene impostata a true, per cui pensavo stupidamente di non passare più dalla procedura di inizializzazione. Cosa che non è affatto vera. Per esempio, con il codice seguente…

DataProvider<ArrayList>.MakeSomeOperation(); DataProvider<ArrayList>.MakeSomeOperation(); DataProvider<StringBuilder>.MakeSomeOperation();

…utilizzo tre volte la classe DataProvider. Le prime due chiamate usano T come se fosse un ArrayList; la terza ed ultima chiamata usa T come se fosse uno StringBuilder. Ho dovuto usare due classi con il costruttore vuoto, dato il constraint applicato al generics.

Alla prima chiamata (ArrayList) avviene l’inizializzazione.
Alla seconda chiamata (ArrayList) l’inizializzazione non avviene più.
Alla terza chiamata (StringBuilder) l’inizializzazione viene eseguita ancora una volta.

Ogni volta che cambio il Type assunto da T, la classe statica DataProvider viene reistanziata per quel particolare tipo, e quindi viene nuovamente scatenata l’esecuzione di initialize(). Ci sarebbe un modo per evitarlo, cioè spostare la definizione del generics dal nome della classe al nome del metodo. Però, ovviamente, dipende da quello che dobbiamo fare, mica è detto che debba per forza sempre essere così!

Technorati Tags:  

Send to Kindle
.NET World

Progetti Flickr su CodePlex

CodePlex.com ha tre progetti taggati con il tag Flickr. Essi sono:

Vista Flickr Uploader

Flickr Metadata Synchr

MeiRou – A Flickr Photo Management Tool

Mi interessano di più il primo e l’ultimo. Il secondo è un po’ troppo macchinoso, perchè sincronizza un folder locale ad un set fotografico di Flickr. Non mi interessa, perchè secondo me fa più casini che altro. Non me ne voglia l’autore. Tutti e tre i progetti sono in WPF, perciò secondo me può essere interessante dargli un’occhiata.

Technorati Tags:   

Send to Kindle