This article has been localized into Italian by the community.
Il controllo ListBox
Nell'ultimo articolo, abbiamo dato un'occhiata all' ItemsControl, che è con ogni probabilità la lista più semplice in WPF. La ListBox è il controllo successivo che aggiunge una qualche funzionalità in più. Una delle principali differenze risiede nel fatto che la ListBox tratta attualmente con le selezioni, dando all'utente la possibilità di selezionare uno o più elementi nella lista e restituendo automaticamente il risultato visivo.
Ecco un esempio di controllo ListBox molto semplice:
<Window x:Class="WpfTutorialSamples.ListBox_control.ListBoxSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListBoxSample" Height="120" Width="200">
<Grid Margin="10">
<ListBox>
<ListBoxItem>ListBox Item #1</ListBoxItem>
<ListBoxItem>ListBox Item #2</ListBoxItem>
<ListBoxItem>ListBox Item #3</ListBoxItem>
</ListBox>
</Grid>
</Window>
Tutto ciò è semplice come appare: dichiariamo un controllo ListBox e al suo interno dichiariamo tre ListBoxItem, ognuno con il proprio testo. Tuttavia, poiché il ListBoxItem è in realtà un ContentControl, possiamo definire contenuti personalizzati per esso:
<Window x:Class="WpfTutorialSamples.ListBox_control.ListBoxSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListBoxSample" Height="120" Width="200">
<Grid Margin="10">
<ListBox>
<ListBoxItem>
<StackPanel Orientation="Horizontal">
<Image Source="/WpfTutorialSamples;component/Images/bullet_blue.png" />
<TextBlock>ListBox Item #1</TextBlock>
</StackPanel>
</ListBoxItem>
<ListBoxItem>
<StackPanel Orientation="Horizontal">
<Image Source="/WpfTutorialSamples;component/Images/bullet_green.png" />
<TextBlock>ListBox Item #2</TextBlock>
</StackPanel>
</ListBoxItem>
<ListBoxItem>
<StackPanel Orientation="Horizontal">
<Image Source="/WpfTutorialSamples;component/Images/bullet_red.png" />
<TextBlock>ListBox Item #3</TextBlock>
</StackPanel>
</ListBoxItem>
</ListBox>
</Grid>
</Window>
Per ciascuno degli elementi ListBoxItem ora aggiungiamo uno StackPanel, in cui aggiungiamo un'immagine e un blocco di testo. Questo ci dà il pieno controllo sul contenuto così come sul rendering di testo, come si può vedere dallo screenshot, in cui sono stati usati colori diversi per ciascuno dei numeri.
Dallo screenshot potresti anche notare un'altra differenza confrontando ItemsControl con ListBox: per impostazione predefinita, attorno al controllo viene mostrato un bordo, facendolo apparire effettivamente come un controllo anziché solo output.
Collegamento dati al ListBox
La definizione manuale degli elementi per ListBox costituisce un ottimo primo esempio, ma la maggior parte delle volte, i controlli ListBox verranno riempiti con elementi provenienti da una origine dati utilizzando l'associazione (databinding). Per impostazione predefinita, se si associa un elenco di elementi a ListBox, il loro metodo ToString() verrà utilizzato per rappresentare visivamente ciascun elemento. Questo è raramente quello che si vuole, ma fortunatamente, possiamo dichiarare con facilità un modello che verrà usato per renderizzare ogni elemento.
Ho riutilizzato l'esempio basato su TODO nel paragrafo sugli ItemsControl, dove costruiamo un fantastico elenco TODO usando una semplice classe nel Code-behind e, in questo caso, un controllo ListBox per la rappresentazione visiva. Ecco l'esempio:
<Window x:Class="WpfTutorialSamples.ListBox_control.ListBoxDataBindingSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListBoxDataBindingSample" Height="150" Width="300">
<Grid Margin="10">
<ListBox Name="lbTodoList" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0,2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Title}" />
<ProgressBar Grid.Column="1" Minimum="0" Maximum="100" Value="{Binding Completion}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
using System;
using System.Windows;
using System.Collections.Generic;
namespace WpfTutorialSamples.ListBox_control
{
public partial class ListBoxDataBindingSample : Window
{
public ListBoxDataBindingSample()
{
InitializeComponent();
List<TodoItem> items = new List<TodoItem>();
items.Add(new TodoItem() { Title = "Complete this WPF tutorial", Completion = 45 });
items.Add(new TodoItem() { Title = "Learn C#", Completion = 80 });
items.Add(new TodoItem() { Title = "Wash the car", Completion = 0 });
lbTodoList.ItemsSource = items;
}
}
public class TodoItem
{
public string Title { get; set; }
public int Completion { get; set; }
}
}
Tutta la magia accade nell'ItemTemplate che abbiamo definito per ListBox. Lì, specifichiamo che ogni elemento ListBox deve essere costituito da una griglia, diviso in due colonne, con un TextBlock che mostra il titolo nella prima colonna e un ProgressBar che mostra lo stato di completamento nella seconda colonna. Per estrarre il valore, usiamo un semplice abbinamento dati, che è tutto spiegato nella parte di associazione (dataBinding) di questo tutorial.
Nel file Code-behind, abbiamo dichiarato una classe TodoItem molto semplice per contenere ciascuno dei nostri articoli TODO. Nel costruttore della finestra, inizializziamo una lista, aggiungiamo tre elementi TODO ad essa e quindi la assegniamo alla ItemsSource di ListBox. Come si può vedere, ciò di cui ha bisogno WPF per mostrare una lista di TODO, è la combinazione di ItemsSource e ItemTemplate che abbiamo specificato nella parte XAML.
Si noti la proprietà HorizontalContentAlignment che ho impostato su Stretch su ListBox. L'allineamento del contenuto predefinito per un oggetto ListBox è Left, il che significa che ogni elemento occupa solo lo spazio orizzontale necessario.
Usando l'allineamento di Stretch, ogni elemento viene allungato per occupare l'intero spazio disponibile, come puoi vedere dallo screenshot precedente.
Lavorare con le selezioni del controllo ListBox
Come accennato, una differenza fondamentale tra ItemsControl e ListBox è che ListBox gestisce e visualizza la selezione dell'item. Pertanto, molte domande di ListBox riguardano la selezione. Per rispondere a queste domande, ho creato un esempio più ampio, mostrando alcuni trucchi relativi alla selezione:
<Window x:Class="WpfTutorialSamples.ListBox_control.ListBoxSelectionSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListBoxSelectionSample" Height="250" Width="450">
<DockPanel Margin="10">
<StackPanel DockPanel.Dock="Right" Margin="10,0">
<StackPanel.Resources>
<Style TargetType="Button">
<Setter Property="Margin" Value="0,0,0,5" />
</Style>
</StackPanel.Resources>
<TextBlock FontWeight="Bold" Margin="0,0,0,10">ListBox selection</TextBlock>
<Button Name="btnShowSelectedItem" Click="btnShowSelectedItem_Click">Show selected</Button>
<Button Name="btnSelectLast" Click="btnSelectLast_Click">Select last</Button>
<Button Name="btnSelectNext" Click="btnSelectNext_Click">Select next</Button>
<Button Name="btnSelectCSharp" Click="btnSelectCSharp_Click">Select C#</Button>
<Button Name="btnSelectAll" Click="btnSelectAll_Click">Select all</Button>
</StackPanel>
<ListBox Name="lbTodoList" HorizontalContentAlignment="Stretch" SelectionMode="Extended" SelectionChanged="lbTodoList_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0,2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Title}" />
<ProgressBar Grid.Column="1" Minimum="0" Maximum="100" Value="{Binding Completion}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</Window>
using System;
using System.Windows;
using System.Collections.Generic;
namespace WpfTutorialSamples.ListBox_control
{
public partial class ListBoxSelectionSample : Window
{
public ListBoxSelectionSample()
{
InitializeComponent();
List<TodoItem> items = new List<TodoItem>();
items.Add(new TodoItem() { Title = "Complete this WPF tutorial", Completion = 45 });
items.Add(new TodoItem() { Title = "Learn C#", Completion = 80 });
items.Add(new TodoItem() { Title = "Wash the car", Completion = 0 });
lbTodoList.ItemsSource = items;
}
private void lbTodoList_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if(lbTodoList.SelectedItem != null)
this.Title = (lbTodoList.SelectedItem as TodoItem).Title;
}
private void btnShowSelectedItem_Click(object sender, RoutedEventArgs e)
{
foreach(object o in lbTodoList.SelectedItems)
MessageBox.Show((o as TodoItem).Title);
}
private void btnSelectLast_Click(object sender, RoutedEventArgs e)
{
lbTodoList.SelectedIndex = lbTodoList.Items.Count - 1;
}
private void btnSelectNext_Click(object sender, RoutedEventArgs e)
{
int nextIndex = 0;
if((lbTodoList.SelectedIndex >= 0) && (lbTodoList.SelectedIndex < (lbTodoList.Items.Count - 1)))
nextIndex = lbTodoList.SelectedIndex + 1;
lbTodoList.SelectedIndex = nextIndex;
}
private void btnSelectCSharp_Click(object sender, RoutedEventArgs e)
{
foreach(object o in lbTodoList.Items)
{
if((o is TodoItem) && ((o as TodoItem).Title.Contains("C#")))
{
lbTodoList.SelectedItem = o;
break;
}
}
}
private void btnSelectAll_Click(object sender, RoutedEventArgs e)
{
foreach(object o in lbTodoList.Items)
lbTodoList.SelectedItems.Add(o);
}
}
public class TodoItem
{
public string Title { get; set; }
public int Completion { get; set; }
}
}
Come puoi vedere, ho definito una serie di pulsanti a destra di ListBox, per ottenere o manipolare la selezione. Ho anche modificato la modalità SelectionMode in Extended, per consentire la selezione di più elementi. Questo può essere fatto a livello di codice, come io ho fatto nell'esempio, o dall'utente finale, tenendo premuto [Ctrl] o [Maiusc] mentre si fa clic sugli elementi.
Per ciascuno dei pulsanti, ho definito un gestore dell'evento click nel codice. Ogni azione dovrebbe essere piuttosto esplicativa e il codice C# utilizzato è abbastanza semplice, ma se siete ancora in dubbio, provate a eseguire l'esempio sul vostro computer e provate le varie possibilità nell'esempio.
Riassunto
Il controllo ListBox è molto simile al controllo ItemsControl e possono essere utilizzate molte delle stesse tecniche. ListBox offre un po' più di funzionalità rispetto a ItemsControl, in particolare la gestione della selezione. Per ulteriori funzionalità, come le intestazioni di colonna, dovreste dare un'occhiata al controllo ListView, di cui viene data una descrizione molto approfondita più avanti in questo tutorial con diversi articoli che spiegano tutte le funzionalità.