André Alves de Lima

Talking about Software Development and more…

Imprimindo conteúdo do DataGridView no Crystal Reports

Você que utiliza o DataGridView para entrada de dados no seu sistema Windows Forms sem necessariamente estar ligado a algum banco de dados, já pensou em imprimir as informações do grid? Uma opção é imprimir o controle em si, mas, muito provavelmente essa não é a opção que traz uma melhor experiência para o usuário. Que tal imprimir o conteúdo do DataGridView no Crystal Reports? Se essa ideia te interessou, continue lendo esse artigo para conferir como implementar essa funcionalidade.

Criando o formulário com DataGridView

Primeiramente, vamos começar criando um novo projeto do tipo “Windows Forms Application“. Na verdade, poderíamos utilizar a mesma lógica deste artigo em outros tipos de projeto (como WPF, Web Forms ou MVC). Só escolhi o Windows Forms por ser mais fácil de demonstrar e por ser o mais conhecido no mercado.

Uma vez criado o projeto, vamos ajustar o formulário, adicionando um DataGridView e algumas colunas (com os nomes “FuncionarioID“, “Nome” e “Sobrenome“). Além disso, vamos colocar um botão logo abaixo do grid que servirá para chamarmos o outro formulário que apresentará o relatório:

Após esse ponto, se executarmos a aplicação, veremos que o grid está funcional, ou seja, podemos adicionar algumas linhas:

E agora? Como criar o relatório?

Uma vez estando o DataGridView já preparado e funcional, vamos criar um novo relatório do Crystal Reports. Dê o nome de “RelatorioFuncionario” para o novo relatório que será criado e escolha a opção de gerar o relatório em branco:

Agora é que surge o problema: como é que escolhemos uma fonte de dados para o relatório? Se olharmos na janela “Database Expert” do Crystal Reports, não encontraremos nenhum DataSet ou classe de dados para utilizarmos no nosso relatório:

E agora? Como desenhamos o relatório sem termos um DataSet ou classe de dados no nosso projeto? A verdade é que é possível gerar a definição de campos manualmente no Crystal Reports através de arquivos TTX, porém, eu não recomendo. A razão para isso é que, mesmo que você não utilize um DataSet ou classe para fazer o design do relatório, você obrigatoriamente terá que passar um DataSet ou coleção de objetos para alimentar o relatório do Crystal Reports (essas são as duas únicas opções de passar dados para o Crystal Reports através de aplicações .NET). Dessa forma, já que teremos que criar um DataSet ou classe para passar os dados para o Crystal Reports, compensa muito mais utilizá-los na hora da definição do relatório.

Dessa forma, vamos ver a seguir como criar um DataSet e como criar uma classe para desenharmos o relatório e alimentarmos com as linhas cadastradas no grid.

Criando o relatório com um DataSet

Primeiramente, vamos ver como podemos criar um DataSet com as informações cadastradas no grid. Já que vamos criar um DataSet, vamos cria-lo como DataSet tipado. Para isso, adicione um novo item ao projeto utilizando o tipo “DataSet” (que está localizado dentro da categoria “Data“). Dê o nome de “DataSetRelatorio” para o novo DataSet e adicione uma nova tabela chamada “Funcionario“:

Em seguida, se voltarmos para a tela de “Database Expert” no Crystal Reports, veremos que o DataSet estará disponível para a utilização no relatório:

Adicione essa tabela ao relatório e trabalhe no design dele de forma que ele fique parecido com a imagem abaixo:

OK. Agora que já temos o relatório desenhado, vamos criar um novo formulário para exibi-lo. Para isso, adicione um novo formulário no projeto, dando o nome de “FormRelatorio“. Dentro desse formulário, adicione um controle do Crystal Reports e selecione o relatório que acabamos de desenhar:

Logo em seguida, vamos até o code-behind do formulário para adicionarmos um novo construtor recebendo o DataSet que alimentará o relatório:

        // C#
        public FormRelatorio(DataSet dataSet) : this()
        {
            RelatorioFuncionario1.SetDataSource(dataSet);
            crystalReportViewer1.RefreshReport();
        }
    ' VB.NET
    Public Sub New()
        ' This call is required by the designer.
        InitializeComponent()
    End Sub

    Public Sub New(DataSet As DataSet)
        Me.New()
        RelatorioFuncionario1.SetDataSource(DataSet)
        CrystalReportViewer1.RefreshReport()
    End Sub

Feito isso, agora podemos voltar para o nosso formulário inicial para implementarmos a ação do botão “Relatório“. Como temos que passar um DataSet para o formulário de relatórios, teremos que fazer um “foreach” nas linhas do grid para alimentarmos uma instância do DataSet que criamos anteriormente:

            // C#
            //Opção 1 - Criando DataSet "na mão":
            var dataSet = new DataSetRelatorio();
            foreach (DataGridViewRow linha in dataGridView1.Rows)
            {
                if (!linha.IsNewRow)
                {
                    var novaLinhaDataSet = dataSet.Funcionario.NewFuncionarioRow();

                    novaLinhaDataSet.FuncionarioID = linha.Cells["FuncionarioID"].Value.ToString();
                    if (linha.Cells["Nome"].Value != null)
                        novaLinhaDataSet.Nome = linha.Cells["Nome"].Value.ToString();
                    if (linha.Cells["Sobrenome"].Value != null)
                        novaLinhaDataSet.Sobrenome = linha.Cells["Sobrenome"].Value.ToString();

                    dataSet.Funcionario.AddFuncionarioRow(novaLinhaDataSet);
                }
            }

            var formRelatorio = new FormRelatorio(dataSet);
            formRelatorio.Show();
        ' VB.NET
        ' Opção 1 - Criando DataSet "na mão"
        Dim DataSet As New DataSetRelatorio()
        For Each Linha As DataGridViewRow In dataGridView1.Rows
            If Not Linha.IsNewRow Then
                Dim NovaLinhaDataSet = DataSet.Funcionario.NewFuncionarioRow()

                NovaLinhaDataSet.FuncionarioID = Linha.Cells("FuncionarioID").Value.ToString()
                If Linha.Cells("Nome").Value <> Nothing Then
                    NovaLinhaDataSet.Nome = Linha.Cells("Nome").Value.ToString()
                End If
                If Linha.Cells("Sobrenome").Value <> Nothing Then
                    NovaLinhaDataSet.Sobrenome = Linha.Cells("Sobrenome").Value.ToString()
                End If

                DataSet.Funcionario.AddFuncionarioRow(NovaLinhaDataSet)
            End If
        Next
        Dim FormRelatorio As New FormRelatorio(DataSet)
        FormRelatorio.Show()

Execute a aplicação, adicione algumas linhas no grid, clique no botão “Relatório” e veja que os dados digitados no grid serão passados para o relatório, justamente como esperado:

Nota: se você receber uma “FileNotFoundException” vindo do controle do Crystal Reports ao executar o projeto, isso quer dizer que falta uma configuração no seu arquivo app.config. Eu mostrei como fazer essa configuração no artigo: Trabalhando com o Crystal Reports no WPF.

Apesar dessa metodologia ter funcionado, ela não é a mais indicada. Como temos que criar o DataSet de qualquer maneira para alimentarmos o relatório, seria muito mais vantajoso fazermos o databinding do DataSet com o grid (ao invés de trabalhar sem databinding e ter que criar o DataSet “na mão” antes de exibir o relatório).

O processo de “bindar” o DataSet com o grid é muito simples. Basicamente, nós temos que criar uma nova instância do DataSet no nível do formulário e, no construtor, temos que utilizar essa instância como “DataSource” do DataGridView. Não podemos esquecer de configurarmos a propriedade “AutoGenerateColumns” como “false” (uma vez que nós já criamos as colunas manualmente no DataGridView) e também temos que configurar a propriedade “DataMember” como “Funcionario” (que é o nome da DataTable):

    // C#
    public partial class FormFuncionarios : Form
    {
        DataSetRelatorio _dataSet = new DataSetRelatorio();

        public FormFuncionarios()
        {
            InitializeComponent();
            // Opção 2 - DataSet "bindado" no DataGridView
            dataGridView1.AutoGenerateColumns = false;
            dataGridView1.DataSource = _dataSet;
            dataGridView1.DataMember = "Funcionario";
        }
    }
' VB.NET
Public Class FormFuncionarios
    Private DataSet As New DataSetRelatorio

    Public Sub New()
        ' This call is required by the designer.
        InitializeComponent()

        ' Opção 2 - DataSet "bindado" no DataGridView
        dataGridView1.AutoGenerateColumns = False
        dataGridView1.DataSource = DataSet
        dataGridView1.DataMember = "Funcionario"
    End Sub
End Class

Com isso, ao invés de termos que criar um novo DataSet para passarmos para o relatório, podemos utilizar esse DataSet que acabamos de criar no nível do formulário. Como ele está “bindado” com o grid, todas as linhas que forem criadas no grid serão passadas para o relatório. Nesse caso, o código para exibirmos o formulário do relatório fica muito mais simples:

            // C#
            // Opção 2 - DataSet "bindado" no DataGridView
            var formRelatorio = new FormRelatorio(_dataSet);
            formRelatorio.Show();
        ' VB.NET
        ' Opção 2 - DataSet "bindado" no DataGridView
        Dim FormRelatorio = New FormRelatorio(DataSet)
        FormRelatorio.Show()

Atenção! Pode ser que você receba um erro parecido com a imagem abaixo ao tentar criar uma nova linha no grid:

Se isso acontecer, significa que ficou faltando configurar a propriedade “DataPropertyName” nas colunas no grid. Essa propriedade serve para ligar as colunas do grid com as colunas da DataTable:

Criando o relatório com uma classe

Agora que já vimos como exibimos o relatório do Crystal Reports utilizando um DataSet, vamos conferir como podemos alimentar o mesmo relatório utilizando instâncias de uma classe? Para isso, vamos adicionar uma nova classe no nosso projeto. Essa classe terá a mesma estrutura da DataTable que criamos anteriormente:

    // C#
    public class DadosRelatorio
    {
        public string FuncionarioID { get; set; }
        public string Nome { get; set; }
        public string Sobrenome { get; set; }
    }
' VB.NET
Public Class DadosRelatorio
    Public Property FuncionarioID As String
    Public Property Nome As String
    Public Property Sobrenome As String
End Class

Com essa nova classe criada, na hora de exibirmos o relatório nós teremos que iterar pelas linhas do grid montando uma lista de instâncias dessa classe baseada nas informações cadastradas no grid. Porém, antes disso, temos que adicionar um construtor no formulário do relatório. Esse novo construtor será muito parecido com o anterior (que recebe um DataSet), mas, nesse caso, ele deverá receber uma coleção (IEnumerable) que alimentará o relatório:

        // C#
        public FormRelatorio(System.Collections.IEnumerable colecao) : this()
        {
            RelatorioFuncionario1.SetDataSource(colecao);
            crystalReportViewer1.RefreshReport();
        }
    ' VB.NET
    Public Sub New(Colecao As IEnumerable)
        Me.New()
        RelatorioFuncionario1.SetDataSource(Colecao)
        CrystalReportViewer1.RefreshReport()
    End Sub

Por fim, vamos ajustar o código do botão “Relatório” para criar uma lista de “DadosRelatorio“, passando-a para o “FormRelatorio“:

            // C#
            // Opção 3 - Criando uma lista "na mão":
            var lista = new List<DadosRelatorio>();
            foreach (DataGridViewRow linha in dataGridView1.Rows)
            {
                if (!linha.IsNewRow)
                {
                    var novoItem = new DadosRelatorio();

                    novoItem.FuncionarioID = linha.Cells["FuncionarioID"].Value.ToString();
                    if (linha.Cells["Nome"].Value != null)
                        novoItem.Nome = linha.Cells["Nome"].Value.ToString();
                    if (linha.Cells["Sobrenome"].Value != null)
                        novoItem.Sobrenome = linha.Cells["Sobrenome"].Value.ToString();

                    lista.Add(novoItem);
                }
            }

            var formRelatorio = new FormRelatorio(lista);
            formRelatorio.Show();
        ' VB.NET
        ' Opção 3 - Criando uma lista "na mão":
        Dim Lista As New List(Of DadosRelatorio)
        For Each Linha As DataGridViewRow In dataGridView1.Rows
            If Not Linha.IsNewRow Then
                Dim NovoItem = New DadosRelatorio()

                NovoItem.FuncionarioID = Linha.Cells("FuncionarioID").Value.ToString()
                If Linha.Cells("Nome").Value <> Nothing Then
                    NovoItem.Nome = Linha.Cells("Nome").Value.ToString()
                End If
                If Linha.Cells("Sobrenome").Value <> Nothing Then
                    NovoItem.Sobrenome = Linha.Cells("Sobrenome").Value.ToString()
                End If

                Lista.Add(NovoItem)
            End If
        Next
        Dim FormRelatorio As New FormRelatorio(Lista)
        FormRelatorio.Show()

Da mesma forma que podemos “bindar” um DataSet com o grid, nós podemos também “bindar” uma lista com o grid. Dessa forma, nós conseguimos simplificar o código da exibição do relatório, uma vez que não seria mais necessária a criação manual da lista na hora de exibirmos o relatório. Para isso, temos que criar uma “BindingList” de “DadosRelatorio” no nível do formulário e setarmos essa lista como “DataSource” do grid no construtor do formulário:

    // C#
    public partial class FormFuncionarios : Form
    {
        BindingList<DadosRelatorio> _lista = new BindingList<DadosRelatorio>();

        public FormFuncionarios()
        {
            InitializeComponent();

            // Opção 4 - Lista "bindada" no DataGridView
            dataGridView1.AutoGenerateColumns = false;
            dataGridView1.DataSource = _lista;
        }
    }
' VB.NET
Public Class FormFuncionarios
    Private Lista As New System.ComponentModel.BindingList(Of DadosRelatorio)

    Public Sub New()
        ' This call is required by the designer.
        InitializeComponent()

        ' Opção 4 - Lista "bindada" no DataGridView
        dataGridView1.AutoGenerateColumns = False
        dataGridView1.DataSource = Lista
    End Sub
End Class

Por fim, o código para exibirmos o relatório ficaria bem simples:

            // C#
            // Opção 4 - Lista "bindada" no DataGridView
            var formRelatorio = new FormRelatorio(_lista);
            formRelatorio.Show();
        ' VB.NET
        ' Opção 4 - Lista "bindada" no DataGridView
        Dim FormRelatorio As New FormRelatorio(Lista)
        FormRelatorio.Show()

Concluindo

Apesar de ser possível criarmos a estrutura de dados de um relatório do Crystal Reports sem utilizarmos um DataSet ou classe (utilizando arquivos TTX), essa não é uma prática recomendada. Como já teremos que criar um DataSet ou classe para alimentarmos o nosso relatório, vale mais a pena criar esse DataSet ou classe antes de confeccionarmos o relatório.

Neste artigo você aprendeu a imprimir o conteúdo de um DataGridView no Crystal Reports, alimentando o relatório com um DataSet ou uma coleção de instâncias de uma classe. Você viu também que é mais recomendado “bindar” o DataSet ou a coleção diretamente com o grid ao invés de ter que construir os dados do relatório antes da sua exibição.

E você, já teve que fazer algo parecido? Como é que você acabou resolvendo essa situação? Conte mais detalhes para a gente na caixa de comentários.

Por fim, convido você a inscrever-se na minha newsletter. Ao fazer isso, 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 logo abaixo.

Até a próxima!

André Lima

Image by Pixabay used under Creative Commons
https://pixabay.com/en/tax-forms-income-business-468440/

Newsletter do André Lima

* indicates required



Powered by MailChimp

28 thoughts on “Imprimindo conteúdo do DataGridView no Crystal Reports

  • Edward Gómez disse:

    Buen día André,

    Excelente explicación gracias por compartir tus conocimientos.

    Saludos desde Colombia

  • Jocildo Schimanscky disse:

    Excelente artigo. Andei à procura dele a bastante tempo.
    Como é que faço para implementá-lo em C#???

    • andrealveslima disse:

      Olá Jocildo,

      Como comentei via e-mail, os exemplos deste artigo estão apresentados tanto em C# quanto em VB.NET.. Caso você fique com alguma dúvida específica sobre a implementação dele em C#, é só falar..

      Abraço!
      André Lima

  • Robson disse:

    Andre BOA TARDE MEU NOME É ROBSON TENHO DIFICUDADES EM UMA CRIAR UMA EXEMPLOR DE VALIDAÇÃO DE LICENÇA MENSAL EM UM PROGRAMA NA LINGUAGEM VB.NET ANDREA POR FAVOR VOÇE PODE MANDAR PARA MEU EMAIL UM EXEMPLO SIMPLES MEU EMAIL É ROBSON.C2016@Outlook.com por favor já fiz varias buscas na internet e nada aguardo?

    • andrealveslima disse:

      Olá Robson, obrigado pelo comentário!

      Como assim validação de licença mensal? Você poderia dar mais detalhes do que você está querendo implementar?

      Abraço!
      André Lima

  • Priscila disse:

    Boa noite André,

    Estou fazendo em C#.
    Gostaria de uma ajuda, referente a imprimir o relatório com todo o conteúdo do DatagridView isso eu já estou conseguindo.

    O que não estou conseguindo, é imprimir apenas a linha selecionada do DatagridView.

    Ao selecionar a linha do DataGridView, deveria clicar em um botão para este abrir o formulário, e nele trazer apenas a linha que selecionei.

    Se puder me dar uma ajuda agradeço!

    • andrealveslima disse:

      Olá Priscila, obrigado pelo comentário!

      Nesse caso, eu acredito que você poderia utilizar a propriedade “Selected” da linha do DataGridView para saber se a linha está selecionada ou não.. Aí você só adiciona a linha no DataSet / coleção se a propriedade Selected = true.. Utilizando a mesma lógica que eu apresentei no artigo, você poderia expandir o “if” que checa pelo IsNewRow, verificando também se a linha está selecionada:

      if (!linha.IsNewRow && linha.Selected)
      {
         // Resto do código...
      }
      

      Entendeu a ideia?

      Abraço!
      André Lima

      • Priscila disse:

        Oi André obrigada por responder, mas sinceramente não entendi direito…
        seguinte vou te explicar o que eu já tenho feito…

        no form onde esta o DataGridView (que chama o form do relatorio):
        RelatorioCadastro relcad = new RelatorioCadastro();
        relcad.Show();

        em uma classe separada tenho um método que trata referente ao DataSet:

        public RelCadastro geraRelatorioRelatorioCadastro(String sql)
        {
        this.minhaconexao.Open();//abrindo conexao
        SqlCommand cmd = new SqlCommand(sql, this.minhaconexao);//trata a sql apenas no command, a sql do consultar
        ADP.SelectCommand = cmd;//obrigatoriamente tem que ser um sql command – guiar onde vai pegar o comand
        ADP.Fill(this.DsRelCadastro, “cadastro”);//informar aqui tb o nome das tabelas que serão utilizadas, pois mostrará para onde tem que ir, pois a ponte esta feita
        RelCadastro rptCadastro = new RelCadastro();//cria uma estância para poder abrir o relatório

        rptCadastro.SetDataSource(DsRelCadastro);//coloca o relatório dentro do setdatasource
        return rptCadastro;//retorna o relatório
        }

        e no form do relatório tenho (dessa forma ele já está mostrando todos os registros do form):

        TrataBanco TB = new TrataBanco();

        private void RelatorioCadastro_Load(object sender, EventArgs e)
        {
        RelCadastro rptCadastro = new RelCadastro();
        String sql = “select * from cadastro”;
        rptCadastro = TB.geraRelatorioRelatorioCadastro(sql);
        crystalReportViewer1.ReportSource = rptCadastro;

        }

        Porém como falei só não entendi e não sei a forma de colocar para imprimir apenas a linha selecionada no form

        Se puder me dar uma “luz” rs Agradeço…..

        • andrealveslima disse:

          Olá Priscila!

          Vamos lá.. A tabela de “Cadastro” tem uma chave, certo? Você vai precisar passar a chave do registro selecionado no DataGridView para o construtor do seu Form RelatorioCadastro.. O seu construtor recebendo a chave ficaria assim:

          private int _chave;
          
          public RelatorioCadastro(int chave) : this()
          {
          	_chave = chave;
          }
          

          Depois, ao chamar o formulário do relatório, você teria que pegar o ID do cadastro na linha selecionada no DataGridView (exemplo disponível na documentação do MSDN aqui).. Esse ID você tem que passar para o construtor do formulário RelatorioCadastro:

          // Esse método você tem que implementar com base no link que te passei acima
          int chaveCadastro = PegaChaveCadastroDaLinhaSelecionadaNoDataGridView();
          
          RelatorioCadastro relcad = new RelatorioCadastro(chaveCadastro);
          relcad.Show();
          

          Depois, finalmente, no formulário RelatorioCadastro, na hora que você monta a sentença que vai ser executada no banco, você tem que ajustar o seu SELECT para pegar somente os dados que tenham a chave recebida no construtor:

          	String sql = "select * from cadastro where chave = " + _chave;
          

          Acredito que algo parecido deva resolver o seu problema.. Conseguiu entender a ideia?

          Abraço!
          André Lima

          • Priscila disse:

            Boa noite André, definitivamente não consegui, e sinceramente não sei no que estou errando…
            se vc tiver um tempo e puder dar uma olhada nos códigos….
            https://drive.google.com/drive/folders/0B7Z_K65A1kkvZDhlX0pNVm1ldEE?usp=sharing

            FORM CADASTRO

            using System;
            using System.Collections.Generic;
            using System.ComponentModel;
            using System.Data;
            using System.Drawing;
            using System.Linq;
            using System.Text;
            using System.Threading.Tasks;
            using System.Windows.Forms;
            using System.Data.SqlClient;
            
            namespace Agenda
            {
                public partial class Cadastro : Form
                {
                    public Cadastro()
                    {
                        InitializeComponent();
                    }
            
                    TrataBanco TB = new TrataBanco();
                    CadAgenda ClassAgenda = new CadAgenda();
                    SqlCommand cmd = null;
                    public String OP;
                    
            
                    private void Cadastro_Load(object sender, EventArgs e)
                    {
                        TB.geraDataTableCad();
                        GRDConsulta.DataSource = TB.DTB;
                        GRDConsulta.Columns[0].HeaderText = "Código";
                        GRDConsulta.Columns[1].HeaderText = "Nome";
                        GRDConsulta.Columns[2].HeaderText = "Telefone";
                        GRDConsulta.Columns[3].HeaderText = "Celular";
                        GRDConsulta.Columns[4].HeaderText = "E-mail";
                        GRDConsulta.Columns[5].HeaderText = "Observação";
                        GRDConsulta.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
                        GRDConsulta.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
                        GRDConsulta.Columns[2].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
                        GRDConsulta.Columns[3].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
                        GRDConsulta.Columns[4].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
                        GRDConsulta.Columns[5].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
                        GRDConsulta.Refresh();
                        GRDConsulta.Update();
                    }
            
                    //CRIANDO METODOS
                    //VALIDACAO DE CAMPOS
                    private Boolean Valida()
                    {
                        Boolean v = true;
            
                        if (txtNome.Text == "")
                        {
                            txtNome.BackColor = Color.LightCoral;
                            v = false;
                        }
            
                        if (txtTelefone.Text == "(  )    -")
                        {
                            txtTelefone.BackColor = Color.LightCoral;
                            v = false;
                        }
            
                        return v;
                    }
            
                    //LIMPEZA DA VALIDACAO
                    private void Resete()
                    {
                        txtNome.BackColor = Color.Empty;
                        txtTelefone.BackColor = Color.Empty;
                    }
            
                    //METODO LIMPAR
                    public void Limpar()
                    {
                        txtCodigo.Text = "(novo)";
                        txtNome.Clear();
                        txtTelefone.Clear();
                        txtCelular.Clear();
                        txtEmail.Clear();
                        txtObs.Clear();
                        txtNome.Focus();
                    }
            
                    //METODO PREENCHER
                    public void Preencher()
                    {
                        txtCodigo.Text = GRDConsulta.CurrentRow.Cells[0].Value.ToString();
                        txtNome.Text = GRDConsulta.CurrentRow.Cells[1].Value.ToString();
                        txtTelefone.Text = GRDConsulta.CurrentRow.Cells[2].Value.ToString();
                        txtCelular.Text = GRDConsulta.CurrentRow.Cells[3].Value.ToString();
                        txtEmail.Text = GRDConsulta.CurrentRow.Cells[4].Value.ToString();
                        txtObs.Text = GRDConsulta.CurrentRow.Cells[5].Value.ToString();
                   }
            
                    
                    //BOTAO INSERIR DO TAB CONSULTA
                    private void btnInserir_Click(object sender, EventArgs e)
                    {
                        tabAgenda.SelectedTab = tabCadastro;
                        this.Limpar();
                        this.OP = "Incluir";
                        btnSalvar.Text = "Salvar";
                    }
            
                    //BOTAO ALTERAR DO TAB CONSULTA
                    private void btnAlterar_Click(object sender, EventArgs e)
                    {
                        tabAgenda.SelectedTab = tabCadastro;
                        this.Preencher();
                        this.OP = "Alterar";
                        btnSalvar.Text = "Alteração";
                    }
            
                    //BOTAO EXCLUIR DO TAB CONSULTA
                    private void btnExcluir_Click(object sender, EventArgs e)
                    {
                        tabAgenda.SelectedTab = tabCadastro;
                        this.Preencher();
                        this.OP = "Excluir";
                        btnSalvar.Text = "Confirmar";
                    }
            
                    //BOTAO CONSULTAR DO TAB CONSULTA
                    private void btnConsultar_Click(object sender, EventArgs e)
                    {
                        //SE NENHUM RADIOBUTTON ESTIVER SELECIONADO
                        if (txtBusca.Text == "")
                        {
                            String sql = "Select * from CADASTRO";
                            cmd = new SqlCommand(sql);
                            TB.Consultar(sql);
                            txtBusca.Clear();
                        }
            
                        //SE O RADIOBUTTON NOME ESTIVER SELECIONADO
                        if (rdbNome.Checked == true)
                        {
                            String sql = "Select * from CADASTRO where NOME like '%" + txtBusca.Text + "%'";
                            cmd = new SqlCommand(sql);
                            TB.Consultar(sql);
                            if (GRDConsulta.RowCount == 0)
                            {
                                MessageBox.Show("Não existe nenhum contato com este nome!");
                                TB.geraDataTableCad();
                            }
            
                            txtBusca.Clear();
                            rdbNome.Checked = false;
                        }
            
                        //SE O RADIOBUTTON TELEFONE ESTIVER SELECIONADO
                        if (rdbTelefone.Checked == true)
                        {
                            String sql = "Select * from CADASTRO where TELEFONE like '%" + txtBusca.Text + "%'";
                            cmd = new SqlCommand(sql);
                            TB.Consultar(sql);
                            if (GRDConsulta.RowCount == 0)
                            {
                                MessageBox.Show("Não existe nenhum contato com este nome!");
                                TB.geraDataTableCad();
                            }
            
                            txtBusca.Clear();
                            rdbTelefone.Checked = false;
                        }
            
                        //SE O RADIOBUTTON EMAIL ESTIVER SELECIONADO
                        if (rdbEmail.Checked == true)
                        {
                            String sql = "Select * from CADASTRO where EMAIL like '%" + txtBusca.Text + "%'";
                            cmd = new SqlCommand(sql);
                            TB.Consultar(sql);
                            if (GRDConsulta.RowCount == 0)
                            {
                                MessageBox.Show("Não existe nenhum contato com este nome!");
                                TB.geraDataTableCad();
                            }
            
                            txtBusca.Clear();
                            rdbEmail.Checked = false;
                        }
                    }
            
                    //BOTAO CANCELAR DO TAB CADASTRO
                    private void btnCancelar_Click(object sender, EventArgs e)
                    {
                        //CHAMA O METODO LIMPAR E FECHA A TELA DE CADASTRO
                        this.Limpar();
                        tabAgenda.SelectedTab = tabConsulta;
                    }
            
                    //BOTAO LIMPAR DO TAB CADASTRO
                    private void btnLimpar_Click(object sender, EventArgs e)
                    {
                        this.Limpar();
                    }
            
                    //BOTAO SALVAR DO TAB CADASTRO
                    private void btnSalvar_Click(object sender, EventArgs e)
                    {
                        //INCLUIR
                        if (OP == "Incluir")
                        {
                            if (this.Valida() == true)
                            {
                                ClassAgenda.inserir(txtNome.Text, txtTelefone.Text, txtCelular.Text, txtEmail.Text, txtObs.Text);
                                this.Limpar();
                                this.Resete();
            
                                tabAgenda.SelectedTab = tabConsulta;
                            }
                            else
                            {
                                MessageBox.Show("Existe algum campo em branco!", "Verificar", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                            }
                        }
            
                        //ALTERAR
                        if (OP == "Alterar")
                        {
                            if (this.Valida() == true)
                            {
                                ClassAgenda.alterar(txtNome.Text, txtTelefone.Text, txtCelular.Text, txtEmail.Text, txtObs.Text, int.Parse(txtCodigo.Text));
                                this.Resete();
                                this.Limpar();
            
                                tabAgenda.SelectedTab = tabConsulta;
                            }
                            else
                            {
                                MessageBox.Show("Existe algum campo em branco!", "Verificar", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                            }
            
                        }
                        
                        //EXCLUIR
                        if (OP == "Excluir")
                        {
                            if (MessageBox.Show("Você REALMENTE deseja excluir este registro?", "Confirmação", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.OK)
                            {
                                ClassAgenda.excluir(txtCodigo.Text);
                                btnSalvar.Text = "Confirmar";
            
                                tabAgenda.SelectedTab = tabConsulta;
                            }
                            else
                            {
                                btnSalvar.Text = "Salvar";
                            }
                        }
            
                        TB.geraDataTableCad();
                        GRDConsulta.DataSource = TB.DTB;
                    }
            
            
                    //EXIBE DADOS SELECIONADOS EM UM MESSAGEBOX
                    private void selectedRowsbutton1_Click(object sender, EventArgs e)
                    {
                        int chaveCadastro = GRDConsulta.Rows.GetRowCount(DataGridViewElementStates.Selected);
                        if (chaveCadastro > 0)
                        {
                            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            
                            for (int i = 0; i < chaveCadastro; i++)
                            {
                                sb.Append("Row: ");
                                sb.Append(GRDConsulta.SelectedRows[i].Index.ToString());
                                sb.Append(Environment.NewLine);
                            }
            
                            sb.Append("Total: " + chaveCadastro.ToString());
                            MessageBox.Show(sb.ToString(), "Selected Rows");
                        
                            RelatorioCadastro relcad = new RelatorioCadastro(chaveCadastro);
                            relcad.Show();
                        }
                    }
            
                }
            }
            

            CLASSE TRATA BANCO

            using System;
            using System.Collections.Generic;
            using System.Linq;
            using System.Text;
            using System.Threading.Tasks;
            using System.Data.SqlClient;
            using System.Data;
            using System.Windows.Forms;
            
            namespace Agenda
            {
                class TrataBanco
                {
                    //CONECTANDO COM O BANCO
                    public DataTable DTB = new DataTable();
                    public SqlConnection minhaconexao = new SqlConnection("data source = (local); initial catalog = AGENDA; Integrated Security = SSPI");
                    public SqlDataAdapter ADP = new SqlDataAdapter();
                    DataSet DsRelCadastro = new DataSet();
            
                    //DATATABLE FUNCIONARIOS
                    public void geraDataTableCad()
                    {
                        try
                        {
                            DTB.Clear();
                            SqlCommand CMD = new SqlCommand("Select * from CADASTRO", minhaconexao);
                            ADP.SelectCommand = CMD;
                            ADP.Fill(this.DTB);
                        }
                        catch (Exception Ex)
                        {
                            MessageBox.Show("Erro!\n Não foi possível executar a ação!" + Ex.Message);
                        }
                        finally
                        {
                            minhaconexao.Close();
                        }
                    }
            
                    //CONSULTAR OS DADOS
                    public void Consultar(String sql)
                    {
                        try
                        {
                            DTB.Clear();
                            SqlCommand meucomando = new SqlCommand(sql, this.minhaconexao);
                            ADP.SelectCommand = meucomando;
                            ADP.Fill(this.DTB);
                        }
                        catch (Exception Ex)
                        {
                            MessageBox.Show("Erro! Não foi possível realizar esta operação! \n O" + "erro detectado foi: \n" + Ex.Message);
                        }
                    }
            
                    //RELATÓRIO DE CADASTRO
                    public RelCadastro geraRelatorioRelatorioCadastro(String sql)
                    {
                        this.minhaconexao.Open();//abrindo conexao
                        SqlCommand cmd = new SqlCommand(sql, this.minhaconexao);//trata a sql apenas no command, a sql do consultar
                        ADP.SelectCommand = cmd;//obrigatoriamente tem que ser um sql command - guiar onde vai pegar o comand
                        ADP.Fill(this.DsRelCadastro, "cadastro");//informar aqui tb o nome das tabelas que serão utilizadas, pois mostrará para onde tem que ir, pois a ponte esta feita
                        RelCadastro rptCadastro = new RelCadastro();//cria uma estância para poder abrir o relatório
            
                        rptCadastro.SetDataSource(DsRelCadastro);//coloca o relatório dentro do setdatasource
                        return rptCadastro;//retorna o relatório
                    }
            
                }
            }
            

            FORM RELATORIO CADASTRO

            using System;
            using System.Collections.Generic;
            using System.ComponentModel;
            using System.Data;
            using System.Drawing;
            using System.Linq;
            using System.Text;
            using System.Windows.Forms;
            
            namespace Agenda
            {
                public partial class RelatorioCadastro : Form
                {
                    public RelatorioCadastro()
                    {
                        InitializeComponent();
                    }
            
                    TrataBanco TB = new TrataBanco();
                    
                    private void RelatorioCadastro_Load(object sender, EventArgs e)
                    {
                        
                        
                    }
            
                    private int _chave;
                    
                    public RelatorioCadastro(int chave):this()
                    {
                        _chave = chave;
            
                        RelCadastro rptCadastro = new RelCadastro();
                        String sql = "select * from cadastro where cod = " + _chave;
                        rptCadastro = TB.geraRelatorioRelatorioCadastro(sql);
                        crystalReportViewer1.ReportSource = rptCadastro;
                    }
                    
                    
                }
            }
            
          • andrealveslima disse:

            Olá Priscila!

            Aparentemente está quase tudo correto.. A única coisa que achei estranho é a hora que você está tentando pegar a linha selecionada.. Você está pegando o valor do método GetRowCount para preencher a variável chaveCadastro? Esse método só retorna a quantidade de linhas selecionadas, e não o ID que você tem que utilizar para filtrar o relatório..

            Eu acredito que o código do clique do seu botão deveria ficar mais ou menos assim:

            if (GRDConsulta.SelectedRows.Count > 0)
            {
            	var primeiraLinhaSelecionada = GRDConsulta.SelectedRows[0];
            	var chaveCadastro = Convert.ToInt32(primeiraLinhaSelecionada.Cells["cod"].Value);
            	RelatorioCadastro relcad = new RelatorioCadastro(chaveCadastro);
            	relcad.Show();
            }
            

            Tenta aí e depois avisa se funcionou.. E, se não funcionar, dá mais detalhes do que está acontecendo (por exemplo, se você está recebendo um erro ou se simplesmente o relatório está vindo em branco)..

            Abraço!
            André Lima

  • Olá André!
    Este teu artigo foi o primeiro que me ajudou muito.
    Teus artigos são fantasticos e muito objectivos, continua.
    Muito obrigado

    Abraço!

    • andrealveslima disse:

      Olá Flávio, muito obrigado pelo comentário!

      Fico feliz que este artigo tenha te ajudado.. Pode ficar tranquilo que eu vou continuar produzindo conteúdo aqui por um bom tempo.. :)

      Abraço!
      André Lima

  • Valdemar Paulo disse:

    Ok, André! o meu DataGrid é alimentando pelo Banco de Dados isso é conectei directamente, como ficaria para preencher o Relatório?

  • Alfredo Carruagem disse:

    Vc é o cara. valeu Andre Lima… Obrigador pelo tutorial.

  • WiLL disse:

    Saudações. É possível ao Sr. disponibilizar o código fonte (zipado) deste exemplo?
    Obrigado!

    • andrealveslima disse:

      Olá Will!

      Se eu tivesse eu até passava, mas infelizmente eu não tenho.. Só tenho os projetos de artigos que foram escritos a partir de 2017.. Os mais antigos que isso eu não tenho..

      Mas, é só seguir os passos do artigo que deve dar certinho.. Se ficar com alguma dúvida é só postar aqui..

      Abraço!
      André Lima

  • Jeison disse:

    Olá André,
    é possível desenhar o relatório sem precisar criar o DataSet ou o arquivo TTX?
    Hoje eu tenho uma lista de objetos mas o Crystal não enxerga ela. Daí tenho que ficar populando um dataset na mão só para mandar para o Crystal.
    Abraço!

  • Ola André, tudo bem?
    Tenho lido algum de seus artigos para tentar sair de uma enrascada.
    Estou desenvolvendo uma aplicação ERP web forms com banco MySql.
    Tentei criar relatorios no crystal com classes objeto, mas quando vou add o database ao relatorio ele pede para selecionar um arquivo XML. Sabe me dizer o que acontece:

    • andrealveslima disse:

      Olá Robson!

      Não consegui entender direito o que está acontecendo no seu projeto.. Quando você diz “quando vou add o database ao relatorio ele pede para selecionar um arquivo XML”, o que exatamente você está querendo dizer? Poderia falar os passos que você seguiu para chegar nessa situação (quais opções você clicou, etc)?

      Abraço!
      André Lima

      • Bom dia André,
        Quando adiciono o rpt ao projeto e vou setar o database em .NET objects, para criar o relatório a partir de uma classe, quando seleciono a mesma um form é aberto para informar os dados de conexão: caminho do arquivo e nome da classe. O esperado é um ADO.NET XML.
        Pena que não consigo enviar um print.
        Seria possível um contato por e-mail André? Se possível gostaria de efetuar uma consultoria e acertamos a sua hora técnica.
        Grato pelo retorno.

        • andrealveslima disse:

          Olá Robson!

          Que coisa estranha hein.. Em qual lugar você está indo para setar a estrutura de dados do relatório? Você precisa ir em “Database Expert” e não em “Set Datasource Location”.. Veja como eu fiz neste outro artigo:

          Gerando relatórios do Crystal Reports com Entity Framework

          Quanto a contato via e-mail, o meu endereço é: contato [arroba] andrealveslima [ponto] com [ponto] br.. Infelizmente não estou trabalhando com consultoria no momento, mas podemos conversar sobre as suas dúvidas por e-mail sem problema nenhum..

          Abraço!
          André Lima

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *