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: wpf programming