WPF - Preenchendo uma Combobox


Neste tutorial vou mostrar como preencher um controle Combobox do WPF - Windows Presentation Foundation usando o Visual Studio 2010 Beta 2.

Vou iniciar falando um pouco sobre o controle Combobox da WPF e suas características.

Exibindo itens (texto) em um Combobox

Eu estou usando o Visual Studio 2010 beta 2 nos exemplos citados neste artigo.

Selecione o menu File ->New Project e crie uma nova aplicação do Tipo WPF Application com o nome wpf_Combobox;

O controle ComboBox é muito parecido com o controle ListBox e é muito fácil de usar. No código abaixo estamos usando um controle ComboBox em um controle StackPanel;

Defina o código abaixo no arquivo MainWindow.xaml e observe o resultado da execução do projeto na figura ao lado;

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Preenchendo uma Combobox" Height="286" Width="322">
    <Grid>
        <StackPanel>
            <ComboBox>
                <ComboBoxItem>Item 1</ComboBoxItem>
                <ComboBoxItem>Item 2</ComboBoxItem>
                <ComboBoxItem>Item 3</ComboBoxItem>
                <ComboBoxItem>Item 4</ComboBoxItem>
                <ComboBoxItem>Item 5</ComboBoxItem>
            </ComboBox>
        </StackPanel>
    </Grid>
</Window>

Usando a linguagem XAML declaramos um controle ComboBox usando a tag <ComboBox> e definimos seus itens pela tag <ComboBoxItem>.

O controle ComboBox da WPF permite também tratarmos com elementos complexos como imagens e texto. Vejamos como exibir esses itens...

Exibindo itens com texto e imagem em um Combobox

No menu Project ->Add Window aceite o nome padrão window1.xaml e defina o código abaixo no arquivo window1.xaml;

Nota: Para abrir a janela desejada como janela inicial do projeto clique sobre My Project na janela Solution Explorer e defina o nome da janela no item Startup URI;

<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="395" Width="438">
    <Grid>
        <ComboBox Margin="0,0,12,317">
            <ComboBoxItem>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Width="50">Alegre</TextBlock>
                    <Image Source="C:\dados\alegre.jpg" Height="50" />
                </StackPanel>
            </ComboBoxItem>
            <ComboBoxItem>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Width="50">Elvis</TextBlock>
                    <Image Source="C:\dados\elvis.jpg" Height="50" />
                </StackPanel>
            </ComboBoxItem>
            <ComboBoxItem>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Width="50">Mike</TextBlock>
                    <Image Source="C:\dados\mike.jpg" Height="50" />
                </StackPanel>
            </ComboBoxItem>
        </ComboBox>
    </Grid>
</Window>

Note que estamos usando a combobox para exibir itens com nome e imagem; Fizemos isso usando a tag ComboBoxItem e definindo o texto e a imagem em seu interior.

Vejamos agora como tratar as informações obtidas de um ComboBox como um item selecionado.

Obtendo o item selecionado de um ComboBox

Uma das formas de fazer isso é converter o item selecionado para um item da Combobox e então obter o seu conteúdo para exibi-lo;

No menu Project ->Add Window aceite o nome padrão window2.xaml e defina o código abaixo no arquivo window2.xaml;

Vamos usar uma combobox com os mesmos itens do exemplo anterior. Inclua o código a seguir entre as tags <Grid> no arquivo XAML;

<StackPanel>
    <ComboBox Name=“mComboBox“  >
    <ComboBox Margin="0,0,12,317">
            <ComboBoxItem>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Width="50">Alegre</TextBlock>
                    <Image Source="C:\dados\alegre.jpg" Height="50" />
                </StackPanel>
            </ComboBoxItem>
            <ComboBoxItem>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Width="50">Elvis</TextBlock>
                    <Image Source="C:\dados\elvis.jpg" Height="50" />
                </StackPanel>
            </ComboBoxItem>
            <ComboBoxItem>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Width="50">Mike</TextBlock>
                    <Image Source="C:\dados\mike.jpg" Height="50" />
                </StackPanel>
            </ComboBoxItem>
        </ComboBox>
    </ComboBox>
    <Button Name=“mButton“ Content=“OK“ Click=“mButton_Click“ />
</StackPanel>

Primeiro incluímos um controle ComboBox chamado mComboBox, de forma que podemos identificá-lo e usá-lo no código.

Em seguida incluímos um controle Button (mButton) usado para exibir o que foi selecionado;

A seguir para o exemplo funcionar temos que incluir o código a seguir no evento Click do controle Button:

   Private Sub mButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        Dim cbi As ComboBoxItem = TryCast(mComboBox.SelectedItem, ComboBoxItem)

        If cbi IsNot Nothing Then
            Dim sp As StackPanel = TryCast(cbi.Content, StackPanel)
            Dim bloco As TextBlock = TryCast(sp.Children(0), TextBlock)
            MessageBox.Show("Você selecionou " & bloco.Text)
        Else
            MessageBox.Show("Na selecionado ainda")
        End If

    End Sub

Executando o projeto e selecionando um item após clicar no botão de comando Ok iremos obter:

Vamos entender o código usado:

- Primeiro obtivemos o item atual da ComboBox e armazenei-o na variável cbi;
- Então verifiquei se ele era válido (nothing) (seria o caso do cliente não ter selecionado nada ainda);
- Se fosse inválido (nothing) exibiria a mensagem de item não selecionado;
- Como o conteúdo dos itens da combobox estão na tag ComboBoxItem e são controles StackPanel, foi preciso obter uma referência deles na variável sp;
- A seguir podemos iterar com o filho de um StackPanel, mas como eu conheço o TextBlock eu obtenho o primeiro filho e referencio-o diretamente como elemento zero e retorno na variável de bloco;
- Finalmente obtemos o texto atual da linha que o usuário selecionou;

Vejamos agora como obter informações de uma fonte de dados e exibi-las em um ComboBox.

Exibindo informações de uma fonte de dados em um ComboBox

No menu Project ->Add Window aceite o nome padrão window3.xaml e defina o código abaixo no arquivo window3.xaml;

A partir da ToolBox inclua um elemento Combobox no descritor WPF e em seguida ajuste o seu código no arquivo XAML;

O código no arquivo window3.xaml deverá ser o seguinte:

<Window x:Class="Window3"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window3" Height="300" Width="300">
    <Grid>
        <ComboBox Margin="35,32,25,0" Name="comboBox1" ItemsSource="{Binding}" VerticalAlignment="Top" Height="31">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding ProductName}" Width="100" />
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
    </Grid>
</Window>

No código acima usamos um DataTemplate. Um DataTemplate é um recurso do WPF que permite uma grande flexibilidade para definir a apresentação de dados vinculados, dessa forma os Data templates permitem customizar a aparência de um controle.

No arquivo code-behind Window3.xaml.vb vamos incluir o código que faz o acesso ao banco de dados Northwind.mdb do Microsoft Access e obtém os dados da tabela Products para em seguida preencher o Combobox;

Inclua o código abaixo no evento Window3_Loaded:

Imports System.Data
Imports System.Data.OleDb
Public Class Window3
    Private Sub Window3_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
        Try
            'cria um DataTabale
            Dim dt As New DataTable()
            'define a string de conexão com o MSAccess
            Dim strConn As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\dados\Northwind.mdb;"
            'Abre a conexão
            Dim conn As New OleDbConnection(strConn)
            'cria um DataAdapter selecionando os dados de um tabela do MSAccess
            Dim da As New OleDbDataAdapter("Select ProductID, ProductName from Products", conn)
            'preenche o DataTable
            da.Fill(dt)
            'exibe os dados no DataGridView
            comboBox1.DataContext = dt.DefaultView
        Catch ex As Exception
            MessageBox.Show("Erro : " & ex.Message)
        End Try
    End Sub
End Class

Abaixo vemos o resultado da execução

Se você quiser exibir o código do produto e o nome na combobox como em duas colunas basta alterar a definição no arquivo XAML incluindo a informação que deseja exibir, no caso ProductID;

No exemplo eu inclui um outro controle ComboBox (ComboBox2) e inclui o código do produto(ProductID) como um item a ser exibido:

<Window x:Class="Window3"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window3" Height="300" Width="300">
    <Grid>
        <ComboBox Margin="35,32,25,0" Name="comboBox1" ItemsSource="{Binding}" VerticalAlignment="Top" Height="31">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding ProductName}" Width="100" />
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
        
        <ComboBox Height="36"  Margin="35,88,0,0" Name="ComboBox2" ItemsSource="{Binding}" VerticalAlignment="Top" Width="218">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding ProductID}" Width="70" />
                        <TextBlock Text="{Binding ProductName}" Width="100" />
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
    </Grid>
</Window>

A seguir basta atribuir ao segundo combobox(ComboBox2) a tabela obtida do banco de dados no código do arquivo code-behind:

ComboBox2.DataContext = dt.DefaultView

Executando o projeto após estas alterações teremos:

Se deseja usar o Northwind.mdf do SQL Server 2005/2008 usando um dataset pode usar o código abaixo:

   Private Sub window3_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Dim ds As New DataSet()
        Dim strConn As String = "Server = .\sqlexpress;Database = NorthWind; Integrated Security = SSPI;"
        Dim con As New SqlConnection(strConn)
        Dim cmd As New SqlCommand("select ProductID,ProductName from Products", con)
        Dim sqlDa As New SqlDataAdapter()
        sqlDa.SelectCommand = cmd
        sqlDa.Fill(ds)
       
       ComboBox1.DataContext = ds.Tables(0).DefaultView
    
End Sub

Pegue o projeto completo aqui: wpf_ComboBox.zip(Lembre-se que você precisa do VS2010 beta 2 para abrir o projeto)

Eu sei é apenas WPF , mas eu gosto...

 Referências:


José Carlos Macoratti