L'Object Tree (chiamato anche Visual Tree) è la rappresentazione concettuale dell'interfaccia grafica, la quale è composta da una serie di elementi che possono avere a sua volta uno o più oggetti figlio relazionati fra loro, il risultato è una rappresentazione ad albero. Silverlight permette l'accesso all'Object Tree sia tramite codice JavaScript, sia tramite code-behind.
Tuttavia, la rappresentazione non è composta da proprio tutti gli elementi dell'interfaccia utente: vengono esposti solo gli oggetti che partecipano alla fase di renderizazzione. Anche gli elementi creati e aggiunti dinamicamente via codice procedurale possono interessare l'Object Tree.
Silverlight 2 mette a disposizioni una classe di supporto, VisualTreeHelper (contenuta nel namespace System.Windows.Media
), per accedere alla struttura ad albero.
Vediamo un esempio di utilizzo: creiamo un'interfaccia composta da un serie di elementi, alcuni dei quali aggiunti da codice procedurale. Cominciamo scrivendo il seguente XAML:
<StackPanel x:Name="LayoutRoot" Width="300" VerticalAlignment="Center" HorizontalAlignment="Center" Background="Blue"> <TextBlock Margin="10" Foreground="White" FontSize="28" Text="Contatti" /> <ListBox x:Name="Contacts"> <ListBoxItem Content="Mario Rossi" /> <ListBoxItem Content="Matteo Baglini" /> </ListBox> </StackPanel>
Per creare l'interfaccia usiamo come elemento base uno StackPanel
con sfondo di colore blu, composto da un "header" e da una lista di contatti fittizi. Procediamo aggiungendo due metodi nel code-behind per creare una parte di interfaccia via codice, composta da uno StackPanel
contenente due controlli Button
:
private UIElement CreateChild() { StackPanel panel = new StackPanel(); panel.Orientation = Orientation.Horizontal; panel.HorizontalAlignment = HorizontalAlignment.Right; Button okButton = CreateButton("Conferma"); Button cancelButton = CreateButton("Annulla"); panel.Children.Add(okButton); panel.Children.Add(cancelButton); return panel; } private Button CreateButton(string text) { Button button = new Button(); button.Content = text; button.Margin = new Thickness(5); button.Height = 25; button.Width = 80; return button; }
Per finire, nel costruttore dello UserControl
, richiamiamo il metodo CreateChild
ed aggiungiamo il valore restituito alla collezione di oggetti figlio del controllo primario LayoutRoot
:
public Page() { InitializeComponent(); LayoutRoot.Children.Add(CreateChild()); }
Per visualizzare l'Object Tree tramite la classe VisualTreeHelper
inseriamo nel code-behind un metodo che sarà invocato in maniera ricorsiva e che ci permetterà di percorrere l'albero dei componenti dall'alto verso il basso e stamperà nella console di output del debugger di Visual Studio tutti gli elementi trovati:
private void PrintVisualTree(int depth, DependencyObject obj) { Debug.WriteLine(new string(' ', depth) + obj); for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) PrintVisualTree(depth + 1, VisualTreeHelper.GetChild(obj, i)); }
La chiamata a questo metodo sarà impostata nel gestore dell'evento Load
dello UserControl
, il quale andrà agganciato nel costruttore della classe:
public Page() { InitializeComponent(); LayoutRoot.Children.Add(CreateChild()); Loaded += new RoutedEventHandler(Page_Loaded); } private void Page_Loaded(object sender, RoutedEventArgs e) { PrintVisualTree(0, this); }
Eseguendo l'applicazione con il debugger attivo il risultato sarà il seguente:
Il log mostrato ci permette di capire la macro struttura dello UserControl
primario Page
.