Back-End

12 jun, 2014

C# – DataGridView – Salvando o conteúdo e realizando cálculos

Publicidade

Neste artigo eu vou mostrar como podemos salvar o conteúdo de um controle DataGridView e realizar cálculos que envolvam as células do controle.

Imagine que você tenha um formulário contendo um controle DataGridView, que está sendo usado para incluir informações de itens de um pedido:

c_dgvd5

Nesta interface o usuário poderá digitar diretamente no DataGridView, informando a descrição, a quantidade e o preço, sendo que o valor total é calculado automaticamente pela multiplicação das colunas, quantidade e preço. O total geral exibido em uma caixa de texto abaixo do DataGridView é uma somatória dos valores da coluna Total.

Ao final da entrada dos dados, o usuário poderá clicar no botão Salvar para salvar todos os valores informados no DataGridView.

Então, vamos ver como é que se faz isso.

Criando o projeto

Abra o Visual Studio 2012 Express for Windows desktop e clique em New Project. Escolha a linguagem Visual C# -> Windows e a o template Windows Forms Application informando o nome DataGridView_WF.

No formulário padrão form1.cs, inclua a partir da ToolBox os seguintes controles:

  • 1 DataGridView – gdvItens
  • 1 Button – btnSalvar
  • 1 TextBox – txtTotal

Disponha os controles no formulário conforme o leiaute abaixo:

c_dgvd2

Criando o banco de dados e a tabela

Eu criei um banco de dados chamado Vendas.mdf no SQL Server Local DB e a tabela Itens que possui a seguinte estrutura:

c_dgvd1

A string de conexão do banco de dados está armazenada no arquivo App.Config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<connectionStrings>
     <add name="VendasSQL" connectionString="Data Source=(localDB)\v11.0;Initial Catalog=Vendas;Integrated Security=True"/>
</connectionStrings>
</configuration>

No menu PROJECT, clique em Add Reference e selecione o namespace System.Configuration, que será usado para acessar o arquivo de configuração App.Config.

c_dgvd3

No formulário form1.cs declare os seguintes namespaces:

using System;
using System.Configuration;
using System.Data.SqlClient;
using System.Windows.Forms;

Agora, no evento Load do formulário form1.cs, inclua o código abaixo que acessa o banco de dados Vendas e exibe os registros no controle DataGridView:

private void Form1_Load(object sender, EventArgs e)
  {
            try
            {
                DataTable oTable = new DataTable();
                using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["VendasSQL"].ConnectionString))
                {
                    string sql = "Select * from Itens";
                    con.Open();
                    SqlCommand cmd = new SqlCommand(sql, con);
                    cmd.CommandText = sql;
                    cmd.CommandType = CommandType.Text;
                    SqlDataReader oDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
                    oTable.Load(oDataReader);
                    gdvItens.DataSource = oTable;
                    formataGridView();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
 }

A rotina formataGridView realiza uma formatação no controle DataGridView, permitindo uma exibição formata das colunas:

private void formataGridView()
 {
            var grade = gdvItens;
            grade.AutoGenerateColumns = false;
            grade.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCellsExceptHeaders;
            grade.ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single;
            //altera a cor das linhas alternadas no grid
            grade.RowsDefaultCellStyle.BackColor = Color.White;
            grade.AlternatingRowsDefaultCellStyle.BackColor = Color.Cyan;
            //altera o nome das colunas
            grade.Columns[0].HeaderText = "Id";
            grade.Columns[1].HeaderText = "Descrição";
            grade.Columns[2].HeaderText = "Quantidade";
            grade.Columns[3].HeaderText = "Preco";
            grade.Columns[4].HeaderText = "Total";
            grade.Columns[0].Width = 70;
            grade.Columns[1].Width = 150;
            //formata as colunas valor, vencimento e pagamento
            grade.Columns[3].DefaultCellStyle.Format = "c";
            grade.Columns[4].DefaultCellStyle.Format = "c";
            //seleciona a linha inteira
            grade.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            //não permite seleção de multiplas linhas    
            grade.MultiSelect = false;
            // exibe nulos formatados
            //grade.DefaultCellStyle.NullValue = " - ";
            //permite que o texto maior que célula não seja truncado
            grade.DefaultCellStyle.WrapMode = DataGridViewTriState.True;
            //define o alinhamento à direita
            grade.Columns[3].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
            grade.Columns[4].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
  }

No evento Click, do botão Salvar, temos a chamada para a rotina SalvarDados():

 private void btnSalvar_Click(object sender, EventArgs e)
 {
            SalvarDados();
 }

O código da rotina é mostrado a seguir:

public void SalvarDados()
 {
            try
            {
                if (gdvItens.Rows.Count > 1)
                {
                    for (int i = 0; i <= gdvItens.Rows.Count - 1; i++)
                    {
                         int col1 = Convert.ToInt32(gdvItens.Rows[i].Cells[0].Value); //id
                         string col2 = gdvItens.Rows[i].Cells[1].Value.ToString(); //Descricao 
                         int col3 = Convert.ToInt32(gdvItens.Rows[i].Cells[2].Value); //Quantidade
                         decimal col4 = Convert.ToDecimal(gdvItens.Rows[i].Cells[3].Value); //Preco
                         decimal col5 = Convert.ToDecimal(gdvItens.Rows[i].Cells[4].Value); //Total
                        using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["VendasSQL"].ConnectionString))
                        {
                            string insert = "INSERT INTO Itens(Id,Descricao,Quantidade,Preco,Total) VALUES (@Codigo,@Descricao,@Quantidade,@Preco,@Total)";
                            con.Open();
                            SqlCommand cmd = new SqlCommand(insert, con);
                            cmd.Parameters.AddWithValue("@Codigo", col1);
                            cmd.Parameters.AddWithValue("@Descricao", col2);
                            cmd.Parameters.AddWithValue("@Quantidade", col3);
                            cmd.Parameters.AddWithValue("@Preco", col4);
                            cmd.Parameters.AddWithValue("@Total", col5);
                            cmd.ExecuteNonQuery();
                            con.Close();
                        }
                    }
                }
          MessageBox.Show("Dados incluídos com sucesso !!", "Inclusão", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                ex.Message.ToString();
            }
 }

Este código verifica se existem linhas no controle DataGridView ( dvItens.Rows.Count > 1) e em caso positivo percorre cada uma das linhas atribuindo os valores das células à variáveis.

A seguir abriremos uma conexão com o banco de dados Vendas e definimos a instrução SQL INSERT/INTO, passando os parâmetros para o objeto Command. No método ExecuteNonQuery inclua os valores das células obtidos a partir do DataGridView na tabela Itens.

Para realizar o cálculo automático das colunas Quantidade e Preço vamos usar o evento CellEndEdit, definindo o código abaixo:

private void gdvItens_CellEndEdit(object sender, DataGridViewCellEventArgs e)
 {
            try
            {
                if (e.ColumnIndex == 3)
                {
                    decimal cell1 = Convert.ToDecimal(gdvItens.CurrentRow.Cells[2].Value);
                    decimal cell2 = Convert.ToDecimal(gdvItens.CurrentRow.Cells[3].Value);
                    if (cell1.ToString() != "" && cell2.ToString() != "")
                    {
                        gdvItens.CurrentRow.Cells[4].Value = cell1 * cell2;
                    }
                }
                decimal valorTotal = 0;
                string valor = "";
                if (gdvItens.CurrentRow.Cells[4].Value != null)
                {
                    valor = gdvItens.CurrentRow.Cells[4].Value.ToString();
                    if (!valor.Equals(""))
                    {
                        for (int i = 0; i <= gdvItens.RowCount - 1; i++)
                        {
                            if (gdvItens.Rows[i].Cells[4].Value != null)
                                valorTotal += Convert.ToDecimal(gdvItens.Rows[i].Cells[4].Value);
                        }
                        if (valorTotal == 0)
                        {
                            MessageBox.Show("Nenhum registro encontrado");
                        }
                        txtTotal.Text = valorTotal.ToString("C");
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

No código verificamos se a coluna atual é a coluna Preco (e.ColumnIndex == 3). Em caso positivo, estamos calculando o valor da coluna total:

decimal cell1 = Convert.ToDecimal(gdvItens.CurrentRow.Cells[2].Value);
decimal cell2 = Convert.ToDecimal(gdvItens.CurrentRow.Cells[3].Value);
if (cell1.ToString() != "" && cell2.ToString() != "")
{
         gdvItens.CurrentRow.Cells[4].Value = cell1 * cell2;
}

A seguir verificamos se o valor da coluna Total não é nulo e estamos somando os valores desta coluna e exibindo no controle TextBox.(txtTotal).

Abaixo vemos o projeto em execução:

c_dgvd4

O objetivo deste artigo é mostrar algumas técnicas que podem ser uteis no dia a dia e que você pode adaptar para a sua situação.

Eu não estou encorajando você a usar essa implementação em seu projeto, visto que no exemplo eu tenho código de acesso a dados no formulário e não em uma camada de acesso a dados, como seria o correto.

Alerto também para o fato de que eu não estou realizando validações na entrada de dados, o que é obrigatório fazer em uma aplicação de produção.

Pegue o projeto completo aqui: DataGridView_WF.zip