This article is currently in the process of being translated into Portuguese (~99% done).
The ListBox control
No último artigo, vimos o ItemsControl, que é provavelmente a lista mais simples do WPF. O controle ListBox é o próximo controle na linha, o que adiciona um pouco mais de funcionalidade. Uma das principais diferenças é o fato de que o controle ListBox realmente lida com seleções, permitindo que o usuário final selecione um ou vários itens da lista e automaticamente dê feedback visual para ele.
Aqui está um exemplo de um controle ListBox muito simples:
<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>
Isso é tão simples quanto parece: Declaramos um controle ListBox e, dentro dele, declaramos três ListBoxItem, cada um com seu próprio texto. No entanto, como o ListBoxItem é, na verdade, um ContentControl, podemos definir o conteúdo personalizado para ele:
<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>
Para cada um dos ListBoxItem agora adicionamos um StackPanel, no qual adicionamos uma imagem e um TextBlock. Isso nos dá controle total do conteúdo, bem como da renderização do texto, como você pode ver na captura de tela, onde diferentes cores foram usadas para cada um dos números.
A partir da captura de tela, você também pode notar outra diferença ao comparar o ItemsControl à ListBox: Por padrão, uma borda é mostrada em torno do controle, fazendo com que pareça um controle real em vez de apenas saída.
Ligação de dados do ListBox
Definir itens manualmente para o ListBox faz um bom primeiro exemplo, mas na maioria das vezes, seus controles ListBox serão preenchidos com itens de uma fonte de dados usando a vinculação de dados. Por padrão, se você vincular uma lista de itens ao ListBox, seu método ToString () será usado para representar cada item. Isso raramente é o que você quer, mas, felizmente, podemos facilmente declarar um modelo que será usado para renderizar cada item.
Eu reutilizei o exemplo TODO com base no artigo ItemsControl, onde criamos uma lista TODO legal usando uma classe Code-behind simples e, nesse caso, um controle ListBox para a representação visual. Aqui está o exemplo:
<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; }
}
}
Toda a mágica acontece no ItemTemplate que definimos para o ListBox. Nela, especificamos que cada item do ListBox deve consistir em um Grid, dividido em duas colunas, com um TextBlock mostrando o título no primeiro e um ProgressBar mostrando o status de conclusão na segunda coluna. Para obter os valores, usamos uma ligação de dados muito simples, que é toda explicada na parte de vinculação de dados deste tutorial.
No arquivo Code-behind, declaramos uma classe TodoItem muito simples para armazenar cada um dos nossos itens TODO. No construtor da janela, inicializamos uma lista, adicionamos três itens TODO a ela e a atribuímos ao ItemsSource do ListBox. A combinação de ItemsSource e ItemTemplate que especificamos na parte XAML, isso é tudo o que o WPF precisa para renderizar todos os itens como uma lista TODO.
Observe a propriedade HorizontalContentAlignment que defini como Esticar no ListBox. O alinhamento de conteúdo padrão para um item da ListBox é Esquerda , o que significa que cada item ocupa apenas o espaço horizontal necessário. O resultado? Bem, não é bem o que queremos:
Usando o alinhamento do alongamento, cada item é esticado para ocupar a quantidade total de espaço disponível, como você pode ver na captura de tela anterior.
Trabalhando com a seleção ListBox
Como mencionado, uma diferença fundamental entre o ItemsControl e o ListBox é que o ListBox manipula e exibe a seleção do usuário para você. Portanto, muita questão do ListBox gira em torno de alguma forma trabalhando com a seleção. Para ajudar com algumas dessas perguntas, criei um exemplo maior, mostrando alguns truques relacionados à seleção:
<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; }
}
}
Como você pode ver, eu defini um intervalo de botões à direita da ListBox, para obter ou manipular a seleção. Eu também mudei o SelectionMode para estendido , para permitir a seleção de vários itens. Isso pode ser feito de forma programática, como no exemplo ou pelo usuário final, pressionando [Ctrl] ou [Shift] enquanto clico nos itens .
Para cada um dos botões, defini um manipulador de cliques no Code-behind. Cada ação deve ser bastante autoexplicativa e o código C # usado é bastante simples, mas se você ainda estiver em dúvida, tente executar o exemplo em sua própria máquina e teste as várias possibilidades no exemplo.
Resumo
O controle ListBox é muito parecido com o ItemsControl e várias das mesmas técnicas podem ser usadas. O ListBox oferece um pouco mais de funcionalidade quando comparado ao ItemsControl, especialmente o tratamento de seleção. Para ainda mais funcionalidade, como cabeçalhos de coluna, você deve dar uma olhada no controle ListView, que é dado uma descrição muito detalhada mais adiante neste tutorial com vários artigos explicando toda a funcionalidade.