Uno dei controlli che Petzold non cita nel suo libro è il TabControl, al punto che pensavo che non fosse compreso tra i controlli nativi di WPF. Ieri, sfogliando MSDN a piacimento, ho raggiunto il namespace System.Windows.Controls e mi capita sottomano proprio la classe TabControl. Quando mi capita di vedere una classe che non sapevo esistesse, mi diverto sempre a guardare la Inheritance Hierarchy, perchè vedendo da cosa deriva una determinata classe si possono intuire caratteristiche o capacità ereditate da altri. In questo caso specifico, ho notato che TabControl eredita anche da ItemsControl, così come la ListBox, i menù, la StatusBar e così via. MSDN dà una descrizione per la classe ItemsControl, che recita così:
Represents a control that can be used to present a collection of items.
La collection di items per un controllo di tipo TabControl non sono nient'altro che i suoi TabItem. L'utente naviga all'interno di un TabControl selezionando il tab che gli interessa: seleziona un Item tra gli Items disponibili, esattamente come accade con una ListBox. Il TabControl è ovviamente definibile via XAML in modo molto semplice:
<TabControl Name="tabSchede">
<TabItem Header="Dati Anagrafici" />
<TabItem Header="Dati Fisici" />
<TabItem Header="Altre Informazioni" />
</TabControl>
Via codice, possiamo capire se un TabControl ha qualche Items accedendo alla proprietà HasItems. La proprietà Header di ciascun TabItem non è semplicemente string, ma può essere un qualsiasi content, esattamente come accade per tutti gli altri controlli di WPF. Ieri sera mi sono divertito a rendere un po' diverso l'header di ciascun TabItem. Per esempio, con XAML possiede utilizzare la notazione nota con property elements e scrivere una cosa simile a questa:
<TabControl Margin="5">
<TabItem>
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<Rectangle Stroke="Black" Fill="Red" Width="10" Height="10" />
<Label Margin="6 2 0 0" Padding="0" Content="Dati Anagrafici" />
</StackPanel>
</TabItem.Header>
</TabItem>
</TabControl>
L'header del TabItem contiene uno StackPanel orizzontale, che contiene a sua volta un piccolo rettangolo colorato ed una semplice Label con del testo. Ho giocherellato con Padding e Margin per posizionare gli elementi in modo decente. Ipotizzo che avremmo potuto usare anche la proprietà ItemTemplate, che definisce l'aspetto utilizzato per generare gli items: ci proverò, perchè questa è una cosa che ho solo in testa e non l'ho provata sul campo. La cosa interessante è che i TabItem possono anche essere generati dal runtime di WPF via data-binding, perchè è sufficiente bindare ItemsSource così come faremmo con una ListBox.
Ovviamente, ogni TabItem ha una proprietà Content che definisce il contenuto reale di ogni tab. Il più delle volte il contenuto è organizzato con un altro Panel (la Grid, per esempio) per posizionare i vari controlli che ci interessa vedere sulla Window. La proprietà TabStripPlacement permette di decidere dove vogliamo vedere i tab del TabControl (Top, Bottom, Left o Right). La proprietà SelectedItem ci dà un riferimento al TabItem correntemente selezionato, mentre SelectedIndex il suo indice.
Basta dare un'occhiata all'elenco delle public properties del TabControl per capire come sia possibile applicare diversi stili o template ad ogni elemento che compone il controllo, fornendo un'ampia gamma di possibilità per personalizzare l'aspetto del TabControl stesso.