19 04 2017
Adicionando um ComboBox no DataGridView
Hoje eu vou mostrar para você um tema que pode parecer bem simples se você já tem alguma experiência com desenvolvimento de aplicações desktop na plataforma Microsoft, mas que acaba sendo uma grande dor de cabeça para quem está começando: como podemos adicionar um ComboBox no DataGridView?
Nesse caso, temos duas opções: ou criamos uma lista fixa direto no ComboBox, ou alimentamos o ComboBox com uma fonte de dados. Ambas as opções são bem tranquilas de serem implementadas, porém, existe uma pequena diferença caso precisemos ordenar os itens do nosso ComboBox.
Confira no vídeo um passo a passo mostrando como adicionar um ComboBox no DataGridView utilizando essas duas estratégias:
O projeto base
A construção do exemplo desse vídeo toma como base um projeto bem descomplicado, que na realidade é um simples formulário com um DataGridView e três colunas:
No code-behind do formulário nós carregamos manualmente o grid utilizando uma DataTable:
// C# public Form1() { InitializeComponent(); var dt = new DataTable(); dt.Columns.Add("ID", typeof(int)); dt.Columns.Add("Nome"); dt.Columns.Add("Cidade", typeof(int)); dt.Rows.Add(1, "André", 1);// "Limeira"); dt.Rows.Add(2, "Fulano", 2);// "São Paulo"); dt.Rows.Add(3, "Beltrano", 3);// "Rio de Janeiro"); dt.Rows.Add(4, "Sicrano", 4);//"Brasília"); dataGridView1.DataSource = dt; }
' VB.NET Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load Dim Dt = New DataTable() Dt.Columns.Add("ID", GetType(Integer)) Dt.Columns.Add("Nome") Dt.Columns.Add("Cidade") Dt.Rows.Add(1, "André", "Limeira") Dt.Rows.Add(2, "Fulano", "São Paulo") Dt.Rows.Add(3, "Beltrano", "Rio de Janeiro") Dt.Rows.Add(4, "Sicrano", "Brasília") DataGridView1.DataSource = Dt End Sub
Uma outra opção para carregarmos os dados do DataGridView seria trabalharmos com uma colação de objetos:
// C# var dados = new BindingList<object>(new object[] { new { ID = 1, Nome = "Andre", Cidade = "Limeira" }, new { ID = 2, Nome = "Fulano", Cidade = "São Paulo" }, new { ID = 3, Nome = "Beltrano", Cidade = "Rio de Janeiro" }, new { ID = 4, Nome = "Sicrano", Cidade = "Brasília" } }); dataGridView1.DataSource = dados;
' VB.NET Dim Dados = New System.ComponentModel.BindingList(Of Object)(New Object() _ {New With { .ID = 1, .Nome = "Andre", .Cidade = "Limeira" }, New With { .ID = 2, .Nome = "Fulano", .Cidade = "São Paulo" }, New With { .ID = 3, .Nome = "Beltrano", .Cidade = "Rio de Janeiro" }, New With { .ID = 4, .Nome = "Sicrano", .Cidade = "Brasília" }}) DataGridView1.DataSource = Dados
O resultado final seria exatamente o mesmo. Porém, eu preferi trabalhar com DataTable, pois é a maneira mais utilizada para carregarmos dados em projetos Windows Forms.
A ideia é transformarmos a coluna “Cidade” em um ComboBox onde poderemos selecionar uma opção dentro de uma lista de cidades disponíveis.
Criando um ComboBox fixo
A primeira opção seria criarmos um ComboBox fixo. Para isso, vamos até a lista de colunas do nosso grid, clicando na opção “Edit Columns” da smart tag do controle:
Em seguida, transformamos a coluna “Cidade” em uma “DataGridViewComboBoxColumn“:
Agora que a nossa coluna já é um ComboBox, nós teremos à nossa disposição a propriedade “Items“:
Para termos uma lista fixa, basta digitarmos os itens desejados, um em cada linha:
Execute o projeto e veja o resultado:
É importante notar que, ao transformarmos a coluna em ComboBox, todos os itens que estão sendo utilizados no grid devem estar disponíveis na lista do ComboBox. Caso contrário, receberemos um erro como este ao carregarmos o grid:
Ordenando o ComboBox
Ao trabalharmos com listas fixas no ComboBox, nós podemos facilmente ordenar os seus itens através da propriedade “Sorted“:
Criando um ComboBox dinâmico
Esse tipo de lista fixa pode até ser útil em alguns cenários (como quando queremos criar algum “Status” que tem uma quantidade bem delimitada de opções). Porém, em um cenário mais comum nós provavelmente precisaremos carregar a lista de opções de algum lugar (normalmente do banco de dados). Como é que podemos fazer isso?
Colunas do tipo ComboBox possuem uma propriedade chamada “DataSource“. Nós podemos carregar essa propriedade com uma DataTable ou coleção de objetos que deverão ser mostrados no ComboBox. Por exemplo, para carregarmos o ComboBox com uma DataTable, o código ficaria assim:
// C# var dtCidades = new DataTable(); dtCidades.Columns.Add("Cidade"); dtCidades.Rows.Add("Limeira"); dtCidades.Rows.Add("São Paulo"); dtCidades.Rows.Add("Rio de Janeiro"); dtCidades.Rows.Add("Brasília"); dtCidades.Rows.Add("Fortaleza"); ColumnCidade.ValueMember = "Cidade"; ColumnCidade.DisplayMember = "Cidade"; ColumnCidade.DataSource = dtCidades;
' VB.NET Dim DtCidades = New DataTable() DtCidades.Columns.Add("Cidade") DtCidades.Rows.Add("Limeira") DtCidades.Rows.Add("São Paulo") DtCidades.Rows.Add("Rio de Janeiro") DtCidades.Rows.Add("Brasília") DtCidades.Rows.Add("Fortaleza") ColumnCidade.ValueMember = "Cidade" ColumnCidade.DisplayMember = "Cidade" ColumnCidade.DataSource = DtCidades
Remova a lista de itens que criamos anteriormente na propriedade “Items” da coluna “Cidade” e execute o projeto. O resultado será idêntico ao que tivemos com a lista fixa.
Ordenando um ComboBox com DataSource
Ao utilizarmos uma fonte de dados para o nosso ComboBox, se tentarmos ordená-lo através da propriedade “Sorted“, receberemos um erro:
Nesse caso, nós teremos que ordenar os dados de uma outra maneira. A primeira opção é já trazer os dados ordenados do banco de dados (ou de onde quer que tivermos carregado os dados). Se isso não for possível, nós temos algumas outras opções.
A classe “DataTable” conta com uma propriedade chamada “DefaultView“. Essa propriedade é uma “DataView” onde podemos definir, entre outras coisas, a ordenação padrão da DataTable. Dessa forma, se configurarmos a propriedade “Sort” da “DefaultView“, o ComboBox virá ordenado da maneira que configuramos:
// C# dtCidades.DefaultView.Sort = "Cidade ASC"; ColumnCidade.DataSource = dtCidades;
' VB.NET DtCidades.DefaultView.Sort = "Cidade ASC" ColumnCidade.DataSource = DtCidades
Se por algum acaso essa opção não funcionar, nós podemos também criar manualmente uma outra DataView com base na nossa DataTable, configuramos o “Sort” dessa DataView e passamos essa DataView para o ComboBox (ao invés da DataTable):
// C# var dtView = new DataView(dtCidades); dtView.Sort = "Cidade ASC"; ColumnCidade.DataSource = dtView;
' VB.NET Dim DtView = New DataView(DtCidades) DtView.Sort = "Cidade ASC" ColumnCidade.DataSource = DtView
ValueMember e DisplayMember
Você deve ter percebido que utilizamos as propriedades “ValueMember” e “DisplayMember” na hora de configurarmos a fonte de dados do nosso ComboBox. Qual é o efeito dessas propriedades?
Essas propriedades servem para definirmos colunas específicas para fazermos a ligação entre o item selecionado no ComboBox e a linha do grid. No nosso exemplo, nós estamos armazenando o nome da cidade no grid e estamos alimentando o ComboBox com uma DataTable que só tem uma coluna: “Cidade“. Dessa forma, ambas as propriedades “DisplayMember” e “ValueMember” foram configuradas para “Cidade” (que é o nome da coluna na fonte de dados do ComboBox).
Mas, e se tivéssemos uma coluna “ID” para a cidade (tanto no grid quanto na fonte de dados do ComboBox)? Como é que faríamos para armazenar o “ID” mostrando os nomes das cidades no ComboBox? Simples! Nesse caso nós teríamos que configurar o “ValueMember” como sendo o “ID” e o “DisplayMember” como sendo a coluna onde temos os nomes das cidades (no nosso caso, a coluna se chama “Cidade“).
Veja só como é que ficaria o código:
// C# var dtCidades = new DataTable(); dtCidades.Columns.Add("ID", typeof(int)); dtCidades.Columns.Add("Cidade"); dtCidades.Rows.Add(1, "Limeira"); dtCidades.Rows.Add(2, "São Paulo"); dtCidades.Rows.Add(3, "Rio de Janeiro"); dtCidades.Rows.Add(4, "Brasília"); dtCidades.Rows.Add(5, "Fortaleza"); ColumnCidade.ValueMember = "ID"; ColumnCidade.DisplayMember = "Cidade"; dtCidades.DefaultView.Sort = "Cidade ASC"; ColumnCidade.DataSource = dtCidades; var dt = new DataTable(); dt.Columns.Add("ID", typeof(int)); dt.Columns.Add("Nome"); dt.Columns.Add("Cidade", typeof(int)); dt.Rows.Add(1, "André", 1); dt.Rows.Add(2, "Fulano", 2); dt.Rows.Add(3, "Beltrano", 3); dt.Rows.Add(4, "Sicrano", 4); dataGridView1.DataSource = dt;
' VB.NET Dim DtCidades = New DataTable() DtCidades.Columns.Add("ID", GetType(Integer)) DtCidades.Columns.Add("Cidade") DtCidades.Rows.Add(1, "Limeira") DtCidades.Rows.Add(2, "São Paulo") DtCidades.Rows.Add(3, "Rio de Janeiro") DtCidades.Rows.Add(4, "Brasília") DtCidades.Rows.Add(5, "Fortaleza") ColumnCidade.ValueMember = "ID" ColumnCidade.DisplayMember = "Cidade" DtCidades.DefaultView.Sort = "Cidade ASC" ColumnCidade.DataSource = DtCidades Dim Dt = New DataTable() Dt.Columns.Add("ID", GetType(Integer)) Dt.Columns.Add("Nome") Dt.Columns.Add("Cidade", GetType(Integer)) Dt.Rows.Add(1, "André", 1) Dt.Rows.Add(2, "Fulano", 2) Dt.Rows.Add(3, "Beltrano", 3) Dt.Rows.Add(4, "Sicrano", 4) DataGridView1.DataSource = Dt
Criando a coluna “na mão”
Estou adicionando esta seção alguns dias depois da publicação original porque ela foi enviada como sugestão de um leitor do site. O Marcos Roberto da Fonseca (da empresa ZIPERSoft) me mandou o código que ele utiliza no sistema da empresa dele, onde ele faz a criação das colunas “na mão” (ao invés de utilizar o designer). Achei interessante e, como ele me autorizou compartilhar esse código, aqui vai:
// C# // Criação das colunas var colunaCodigo = new DataGridViewTextBoxColumn(); var colunaTipoPreco = new DataGridViewComboBoxColumn(); // Setando o nome nas colunas colunaCodigo.Name = "colunaCodigo"; colunaTipoPreco.Name = "colunaTipoPreco"; // Configurando o texto do cabeçalho colunaCodigo.HeaderText= "Código"; colunaTipoPreco.HeaderText= "Tipo de preço"; // Populando a coluna ComboBox com itens de um ArrayList var lista = new ArrayList(); lista.Add("VISTA"); lista.Add("PRAZO"); lista.Add("ATACADO"); lista.Add("ALTERNATIVO"); lista.Add("CUSTO"); colunaTipoPreco.Items.AddRange(lista.ToArray()); // Adicionando as colunas no grid seuGrid.Columns.Insert(0, colunaCodigo); seuGrid.Columns.Insert(1, colunaTipoPreco); // Configurando a largura das colunas // Opção 1 - tamanho fixo colunaCodigo.Width = 120; colunaTipoPreco.Width = 190; // Opção 2 - ajuste automático dependendo do conteúdo seuGrid.AutoResizeColumns(); seuGrid.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells; // Configurando colunas como "somente leitura" colunaCodigo.ReadOnly = true; // Configurando a altura da linha do grid seuGrid.RowTemplate.Height = 50;
' VB.NET ' Criação das colunas Dim ColunaCodigo = New DataGridViewTextBoxColumn() Dim ColunaTipoPreco = New DataGridViewComboBoxColumn() ' Setando o nome nas colunas ColunaCodigo.Name = "ColunaCodigo" ColunaTipoPreco.Name = "ColunaTipoPreco" ' Configurando o texto do cabeçalho ColunaCodigo.HeaderText = "Código" ColunaTipoPreco.HeaderText = "Tipo de preço" ' Populando a coluna ComboBox com itens de um ArrayList Dim Lista = New ArrayList() Lista.Add("VISTA") Lista.Add("PRAZO") Lista.Add("ATACADO") Lista.Add("ALTERNATIVO") Lista.Add("CUSTO") ColunaTipoPreco.Items.AddRange(Lista.ToArray()) ' Adicionando as colunas no grid SeuGrid.Columns.Insert(0, ColunaCodigo) SeuGrid.Columns.Insert(1, ColunaTipoPreco) ' Configurando a largura das colunas ' Opção 1 - tamanho fixo ColunaCodigo.Width = 120 ColunaTipoPreco.Width = 190 ' Opção 2 - ajuste automático dependendo do conteúdo SeuGrid.AutoResizeColumns() SeuGrid.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells ' Configurando colunas como "somente leitura" ColunaCodigo.ReadOnly = True ' Configurando a altura da linha do grid SeuGrid.RowTemplate.Height = 50
Baixe o projeto de exemplo
Para baixar o projeto de exemplo desse artigo, assine a minha newsletter. Ao fazer isso, além de ter acesso ao projeto, você receberá um e-mail toda semana sobre o artigo publicado e ficará sabendo também em primeira mão sobre o artigo da próxima semana, além de receber dicas “bônus” que eu só compartilho por e-mail. Inscreva-se utilizando o formulário no final do artigo.
Até a próxima!
Photo by Peter Shanks used under Creative Commons
https://pixabay.com/en/startup-start-up-notebooks-creative-593327/
Song Rocket Power Kevin MacLeod (incompetech.com)
Licensed under Creative Commons: By Attribution 3.0 License
http://creativecommons.org/licenses/by/3.0/
Utilizando a API do Google Drive no C# e VB.NET Impedindo que a aplicação seja executada mais de uma vez ao mesmo tempo
Muito bom Andre, são estes pequenos detalhes que deixam nossas aplicações atraentes.
Valeu Claudionor! Um forte abraço!
André Lima
Parabéns André, como sempre ótimos artigos!
Já pensou em montar um curso do básico ao avançado em Winforms ou WPF?
Eu compraria kkkkk.
Abraços.
Olá Glauco, muito obrigado pelo comentário!
Já pensei em montar um curso desse tipo sim, inclusive eu planejava fazer nesse ano.. Porém, no ano passado eu me sobrecarreguei muito com trabalho (e com o nascimento do meu segundo filho) e quase acabei tendo um burnout, aí resolvi pegar mais leve em 2017 para dar uma recuperada no fôlego.. Ano que vem eu volto com força na criação de produtos, aí talvez saia algum curso sobre Windows Forms / WPF..
Um forte abraço!
André Lima
Excelente artigo como sempre André.
Abraço!
Muito obrigado, Flávio! Fico feliz que você tenha gostado.. :)
Um forte abraço!
André Lima
Muito obrigado!
Perfeita explicação.
De nada, Israel! Qualquer dúvida é só entrar em contato..
Abraço!
André Lima
Muito bom André, ajudou muito.
Mas fiquei com uma dúvida.
Se eu for adicionar uma linha nesse datagridview via fonte, como faço pra “setar” o valor desse comboBox? Tentei com SelectedValue, mas não existe a propriedade.
Olá André, obrigado pelo comentário!
Isso depende se você está alimentando o grid com uma DataSource (por exemplo, uma DataTable) ou se está populando o grid “na mão” (adicionando as linhas diretamente no grid)..
Se você estiver populando o grid com uma DataSource, você deve alterar o valor diretamente na DataSource.. Por exemplo, você deve pegar a linha correspondente na DataTable e setar o valor na coluna correspondente à ComboBox..
Já se você estiver populando o grid “na mão”, você seta o valor da célula específica.. Por exemplo:
Abraço!
André Lima
Olá, em Windows Form, tenho um DataGridView onde uma coluna é combobox e preciso alterar via código a propriedade DisplayStyle, tentei assim não aceita…
itemLocacaoDataGridView.Columns[“NomeDoLivro”].DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing;
Sabe como posso fazer?
Desde já agradeço.
Olá Jair!
Você precisa fazer um cast da coluna antes:
Abraço!
André Lima