This article is currently in the process of being translated into Portuguese (~99% done).
The ComboBox control
O controle ComboBox é de muitas maneiras, como o controle ListBox, mas ocupa muito menos espaço, porque a lista de itens é oculta quando não é necessário. O controle ComboBox é usado em muitos lugares no Windows, mas para ter certeza de que todos saibam como ele é e funciona, vamos direto para um exemplo simples:
<Window x:Class="WpfTutorialSamples.ComboBox_control.ComboBoxSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ComboBoxSample" Height="150" Width="200">
<StackPanel Margin="10">
<ComboBox>
<ComboBoxItem>ComboBox Item #1</ComboBoxItem>
<ComboBoxItem IsSelected="True">ComboBox Item #2</ComboBoxItem>
<ComboBoxItem>ComboBox Item #3</ComboBoxItem>
</ComboBox>
</StackPanel>
</Window>
Na captura de tela, eu ativei o controle clicando nele, fazendo com que a lista de itens fosse exibida. Como você pode ver no código, o ComboBox, em sua forma simples, é muito fácil de usar. Tudo o que fiz aqui é adicionar manualmente alguns itens, tornando um deles o item padrão selecionado, definindo a propriedade IsSelected nele.
Conteúdo personalizado
No primeiro exemplo, mostramos apenas o texto nos itens, o que é bastante comum para o controle ComboBox, mas como o ComboBoxItem é um ContentControl, podemos usar praticamente qualquer coisa como conteúdo. Vamos tentar criar uma lista um pouco mais sofisticada de itens:
<Window x:Class="WpfTutorialSamples.ComboBox_control.ComboBoxCustomContentSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ComboBoxCustomContentSample" Height="150" Width="200">
<StackPanel Margin="10">
<ComboBox>
<ComboBoxItem>
<StackPanel Orientation="Horizontal">
<Image Source="/WpfTutorialSamples;component/Images/bullet_red.png" />
<TextBlock Foreground="Red">Red</TextBlock>
</StackPanel>
</ComboBoxItem>
<ComboBoxItem>
<StackPanel Orientation="Horizontal">
<Image Source="/WpfTutorialSamples;component/Images/bullet_green.png" />
<TextBlock Foreground="Green">Green</TextBlock>
</StackPanel>
</ComboBoxItem>
<ComboBoxItem>
<StackPanel Orientation="Horizontal">
<Image Source="/WpfTutorialSamples;component/Images/bullet_blue.png" />
<TextBlock Foreground="Blue">Blue</TextBlock>
</StackPanel>
</ComboBoxItem>
</ComboBox>
</StackPanel>
</Window>
Para cada um dos ComboBoxItem agora adicionamos um StackPanel, no qual adicionamos uma imagem e um TextBlock. Isso nos dá controle total do conteúdo e da renderização do texto, como você pode ver na captura de tela, em que a cor do texto e a imagem indicam um valor de cor.
Ligação de dados da caixa de combinação
Como você pode ver nos primeiros exemplos, definir manualmente os itens de um controle ComboBox é fácil usando XAML, mas você provavelmente irá em breve encontrar uma situação na qual você precisa que os itens sejam provenientes de algum tipo de fonte de dados, como um banco de dados ou apenas uma lista na memória. Usando a vinculação de dados do WPF e um modelo personalizado, podemos renderizar facilmente uma lista de cores, incluindo uma visualização da cor:
<Window x:Class="WpfTutorialSamples.ComboBox_control.ComboBoxDataBindingSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ComboBoxDataBindingSample" Height="200" Width="200">
<StackPanel Margin="10">
<ComboBox Name="cmbColors">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Rectangle Fill="{Binding Name}" Width="16" Height="16" Margin="0,2,5,2" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
namespace WpfTutorialSamples.ComboBox_control
{
public partial class ComboBoxDataBindingSample : Window
{
public ComboBoxDataBindingSample()
{
InitializeComponent();
cmbColors.ItemsSource = typeof(Colors).GetProperties();
}
}
}
Na verdade, é bem simples: no Code-behind, eu obtenho uma lista de todas as cores usando uma abordagem baseada no Reflection com a classe Colors. Eu o atribuo à propriedade ItemsSource da ComboBox, que então renderiza cada cor usando o modelo que eu defini na parte XAML.
Cada item, conforme definido pelo ItemTemplate, consiste em um StackPanel com um Rectangle e um TextBlock, cada um vinculado ao valor da cor. Isso nos dá uma lista completa de cores, com o mínimo de esforço - e parece muito bom também, certo?
IsEditable
Nos primeiros exemplos, o usuário só pôde selecionar nossa lista de itens, mas uma das coisas legais sobre a ComboBox é que ela suporta a possibilidade de permitir que o usuário selecione uma lista de itens ou insira seu próprio valor. Isso é extremamente útil em situações em que você deseja ajudar o usuário, fornecendo-lhe um conjunto de opções predefinido, enquanto ainda oferece a opção de inserir manualmente o valor desejado. Tudo isso é controlado pela propriedade IsEditable , que altera bastante o comportamento e a aparência do ComboBox:
<Window x:Class="WpfTutorialSamples.ComboBox_control.ComboBoxEditableSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ComboBoxEditableSample" Height="150" Width="200">
<StackPanel Margin="10">
<ComboBox IsEditable="True">
<ComboBoxItem>ComboBox Item #1</ComboBoxItem>
<ComboBoxItem>ComboBox Item #2</ComboBoxItem>
<ComboBoxItem>ComboBox Item #3</ComboBoxItem>
</ComboBox>
</StackPanel>
</Window>
Como você pode ver, posso inserir um valor completamente diferente ou escolher um da lista. Se escolhido da lista, simplesmente sobrescreve o texto do ComboBox.
Como um bônus adorável, o ComboBox tentará automaticamente ajudar o usuário a selecionar um valor existente quando o usuário começar a digitar, como você pode ver na próxima tela, onde eu comecei a digitar "Co":
Por padrão, a correspondência não faz distinção entre maiúsculas e minúsculas, mas é possível defini-lo definindo IsTextSearchCaseSensitive como True. Se você não quiser esse comportamento de preenchimento automático, poderá desativá-lo definindo o IsTextSearchEnabled como False.
Trabalhando com a seleção ComboBox
Uma parte fundamental do uso do controle ComboBox é poder ler a seleção do usuário e até mesmo controlá-la com código. No próximo exemplo, reutilizei o exemplo ComboBox ligado a dados, mas adicionei alguns botões para controlar a seleção. Eu também usei o evento SelectionChanged para capturar quando o item selecionado é alterado, seja por código ou pelo usuário, e aja nele.
Aqui está o exemplo:
<Window x:Class="WpfTutorialSamples.ComboBox_control.ComboBoxSelectionSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ComboBoxSelectionSample" Height="125" Width="250">
<StackPanel Margin="10">
<ComboBox Name="cmbColors" SelectionChanged="cmbColors_SelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Rectangle Fill="{Binding Name}" Width="16" Height="16" Margin="0,2,5,2" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<WrapPanel Margin="15" HorizontalAlignment="Center">
<Button Name="btnPrevious" Click="btnPrevious_Click" Width="55">Previous</Button>
<Button Name="btnNext" Click="btnNext_Click" Margin="5,0" Width="55">Next</Button>
<Button Name="btnBlue" Click="btnBlue_Click" Width="55">Blue</Button>
</WrapPanel>
</StackPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Windows;
using System.Windows.Media;
namespace WpfTutorialSamples.ComboBox_control
{
public partial class ComboBoxSelectionSample : Window
{
public ComboBoxSelectionSample()
{
InitializeComponent();
cmbColors.ItemsSource = typeof(Colors).GetProperties();
}
private void btnPrevious_Click(object sender, RoutedEventArgs e)
{
if(cmbColors.SelectedIndex > 0)
cmbColors.SelectedIndex = cmbColors.SelectedIndex - 1;
}
private void btnNext_Click(object sender, RoutedEventArgs e)
{
if(cmbColors.SelectedIndex < cmbColors.Items.Count-1)
cmbColors.SelectedIndex = cmbColors.SelectedIndex + 1;
}
private void btnBlue_Click(object sender, RoutedEventArgs e)
{
cmbColors.SelectedItem = typeof(Colors).GetProperty("Blue");
}
private void cmbColors_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
Color selectedColor = (Color)(cmbColors.SelectedItem as PropertyInfo).GetValue(null, null);
this.Background = new SolidColorBrush(selectedColor);
}
}
}
A parte interessante deste exemplo são os três manipuladores de eventos para nossos três botões, bem como o manipulador de eventos SelectionChanged . Nos dois primeiros, selecionamos o item anterior ou o próximo, lendo a propriedade SelectedIndex e, em seguida, subtraindo ou adicionando um item a ela. Muito simples e fácil de trabalhar.
No terceiro manipulador de eventos, usamos o SelectedItem para selecionar um item específico com base no valor. Eu faço um pouco de trabalho extra aqui (usando reflexão .NET), porque a ComboBox está vinculada a uma lista de propriedades, cada uma sendo uma cor, em vez de uma simples lista de cores, mas basicamente é tudo sobre dar o valor contido por um dos itens para a propriedade SelectedItem .
No quarto e último manipulador de eventos, respondo ao item selecionado que está sendo alterado. Quando isso acontece, eu leio a cor selecionada (mais uma vez usando Reflection, como descrito acima) e, em seguida, uso a cor selecionada para criar um novo pincel de fundo para a janela. O efeito pode ser visto na imagem.
Se você estiver trabalhando com uma ComboBox editável (propriedade IsEditable definida como true), poderá ler a propriedade Texto para saber o valor que o usuário inseriu ou selecionou.