Quantcast
Channel: Relatórios – André Alves de Lima
Viewing all articles
Browse latest Browse all 61

Multi-relatórios no mesmo formulário com o Report Viewer

$
0
0

Um erro comum que muitas pessoas cometem ao trabalhar com o Report Viewer no Windows Forms é criar um formulário (do Windows Forms) para cada relatório do sistema. Eu diria que o próprio designer do Report Viewer no Visual Studio induz os desenvolvedores a esse erro, uma vez que ele possibilita a escolha do relatório na smart tag do controle. No artigo de hoje, eu vou te mostrar como exibir múltiplos relatórios no mesmo formulário com o Report Viewer.

Criar um formulário para cada relatório não é a melhor maneira de se trabalhar. Imagine que você tenha 15 relatórios no seu sistema. Trabalhando dessa forma, você teria 15 formulários só para fazer a exibição de relatórios. Já pensou se você quiser alterar alguma propriedade do controle do Report Viewer no sistema todo? Por exemplo, digamos que você queira desabilitar o botão de exportação do Report Viewer. Você teria que alterar cada um dos 15 formulários. Nada prático, não é mesmo?

Criando dois relatórios de exemplo

Para exemplificar essa problemática, vamos criar um novo projeto do tipo “Windows Forms Application“. Dentro desse novo projeto, adicione dois DataSets tipados: um chamado “DataSetCliente” e outro chamado “DataSetFornecedor“. No DataSetCliente, adicione uma DataTable chamada “Cliente” e, no DataSetFornecedor, adicione uma DataTable chamada “Fornecedor“:

Feito isso, adicione dois novos relatórios ao projeto: um relatório chamado “ReportCliente” e outro chamado “ReportFornecedor“. Ajuste o layout dos relatórios para que eles fiquem parecidos com as imagens abaixo:

Como você pode perceber, o layout desses relatórios é extremamente simples: um título no cabeçalho do relatório e uma “Table” na área de detalhes listando as informações dos DataSets que criamos anteriormente.

O jeito “errado” – um formulário para cada relatório

Agora que já temos os DataSets e relatórios preparados, precisamos exibi-los de alguma forma. A maneira mais fácil de fazermos isso é criarmos um formulário para cada um desses relatórios. Para fazermos isso, temos que adicionar dois novos formulários ao nosso projeto, arrastarmos um controle do Report Viewer em cada um deles e, finalmente, temos que escolher o relatório desejado utilizando a smart tag do controle:

Em seguida, temos que carregar os dados do DataSet dentro do construtor de cada formulário:

        public FormReportCliente()
        {
            InitializeComponent();

            DataSetCliente.Cliente.AddClienteRow("Cliente 1");
            DataSetCliente.Cliente.AddClienteRow("Cliente 2");
            DataSetCliente.Cliente.AddClienteRow("Cliente 3");
        }
        public FormReportFornecedor()
        {
            InitializeComponent();

            DataSetFornecedor.Fornecedor.AddFornecedorRow("Fornecedor 1");
            DataSetFornecedor.Fornecedor.AddFornecedorRow("Fornecedor 2");
            DataSetFornecedor.Fornecedor.AddFornecedorRow("Fornecedor 3");
            DataSetFornecedor.Fornecedor.AddFornecedorRow("Fornecedor 4");
        }

Finalmente, crie um novo formulário (ou altere o “Form1” que é criado automaticamente pelo Visual Studio) que servirá como menu para chamar um relatório ou outro:

        private void clientesButton_Click(object sender, EventArgs e)
        {
            var reportCliente = new FormReportCliente();
            reportCliente.Show();
        }

        private void fornecedoresButton_Click(object sender, EventArgs e)
        {
            var reportFornecedor = new FormReportFornecedor();
            reportFornecedor.Show();
        }

E com isso conseguimos exibir os dois relatórios sem problema algum. O real problema surge quando quisermos customizar alguma coisa no formulário de exibição dos relatórios no nosso aplicativo. Para isso teríamos que fazer a mesma alteração em cada um dos formulários de exibição de relatórios. Quando só temos dois relatórios até que não é difícil, mas, quanto mais relatórios tivermos no nosso projeto, mais difícil fica a manutenção ao utilizarmos essa sistemática.

A alternativa – um único formulário para todos os relatórios

Após termos conferido o jeito “errado” de exibirmos múltiplos relatórios com o Report Viewer, que tal conferirmos uma alternativa com um custo de manutenção muito mais baixo? A alternativa é criarmos um único formulário que será utilizado para fazermos a exibição de todos os relatórios do nosso sistema. Esse formulário receberá por parâmetro todas as informações necessárias para carregar o relatório e exibi-lo.

Para isso, adicione um novo formulário no projeto, chamado “FormRelatorio“. Esse formulário deverá ter um controle do Report Viewer, porém, não escolheremos nenhum relatório no designer (faremos isso no code-behind utilizando os parâmetros recebidos).

Feito isso, vá para o code-behind do formulário e altere a visibilidade do construtor para “private“. Isso porque criaremos um novo método público e estático no formulário que será encarregado de criar e exibir uma nova instância de “FormRelatorio” (isso facilita a chamada para a exibição de um novo relatório – não se preocupe, você entenderá melhor o motivo daqui a pouco). Além disso, vamos adicionar alguns parâmetros no construtor: “path“, “isEmbeddedResource“, “dataSources” e “reportParameters“:

        private FormRelatorio(string path, bool isEmbeddedResource, Dictionary<string, object> dataSources, Dictionary<string, object> reportParameters = null)
        {
            InitializeComponent();
        }

O parâmetro “path” conterá o caminho para o relatório, que pode ser um arquivo em disco ou um “embedded resource” da aplicação (quando o relatório é adicionado dentro do próprio projeto, como estamos fazendo no exemplo deste artigo). É justamente por esse motivo que precisamos do segundo parâmetro (“isEmbeddedResource“), no qual indicaremos se o “path” corresponde a um caminho em disco ou um caminho para um “embedded resource” do projeto.

Em seguida, temos os parâmetros “dataSources” e “reportParameters“, que são dois dicionários com chave string e valor object. Eles são utilizados para popular as fontes de dados do relatório e os parâmetros necessários para o relatório. Note que “reportParameters” é opcional, uma vez que a maioria dos relatórios não utilizam parâmetros.

E como é que implementamos a lógica para cada um desses parâmetros? Confira no código abaixo:

        private FormRelatorio(string path, bool isEmbeddedResource, Dictionary<string, object> dataSources, Dictionary<string, object> reportParameters = null)
        {
            InitializeComponent();

            // path + isEmbeddedResource.
            if (isEmbeddedResource)
                this.reportViewer.LocalReport.ReportEmbeddedResource = path;
            else
                this.reportViewer.LocalReport.ReportPath = path;

            // dataSources.
            foreach (var dataSource in dataSources)
            {
                var reportDataSource = new Microsoft.Reporting.WinForms.ReportDataSource(dataSource.Key, dataSource.Value);
                this.reportViewer.LocalReport.DataSources.Add(reportDataSource);
            }

            // reportParameters.
            if (reportParameters != null)
            {
                var reportParameterCollection = new List<Microsoft.Reporting.WinForms.ReportParameter>();

                foreach (var parameter in reportParameters)
                {
                    var reportParameter = new Microsoft.Reporting.WinForms.ReportParameter(parameter.Key, parameter.Value.ToString());
                    reportParameterCollection.Add(reportParameter);
                }

                this.reportViewer.LocalReport.SetParameters(reportParameterCollection);
            }
        }

Simples, não? Nós basicamente utilizamos os parâmetros do construtor para configurar o nosso controle do Report Viewer. É justamente isso que é feito no “background” pelo Visual Studio quando você seleciona um relatório específico no designer do Report Viewer.

Agora que já temos o construtor com os parâmetros e a sua implementação, vamos criar aquele método estático que será responsável pela criação e exibição do “FormRelatorio“. Para isso, dentro do “FormRelatorio“, adicione o seguinte método:

        public static void ShowReport(string path, bool isEmbeddedResource, Dictionary<string, object> dataSources, Dictionary<string, object> reportParameters = null)
        {
            var formRelatorio = new FormRelatorio(path, isEmbeddedResource, dataSources, reportParameters);
            formRelatorio.Show();
        }

Finalmente, podemos voltar ao nosso formulário de menu para alterá-lo de forma que ele utilize o nosso “FormRelatorio“. Veja só como fica o código alterado:

        private void clientesButton_Click(object sender, EventArgs e)
        {
            //var reportCliente = new FormReportCliente();
            //reportCliente.Show();

            DataSetCliente dsClientes = new DataSetCliente();
            dsClientes.Cliente.AddClienteRow("Cliente 1");
            dsClientes.Cliente.AddClienteRow("Cliente 2");
            dsClientes.Cliente.AddClienteRow("Cliente 3");

            FormRelatorio.ShowReport(
                "MultiRelatorios.ReportCliente.rdlc",
                true,
                new Dictionary<string, object>() { { "DataSetCliente", dsClientes.Cliente } });
        }

        private void fornecedoresButton_Click(object sender, EventArgs e)
        {
            //var reportFornecedor = new FormReportFornecedor();
            //reportFornecedor.Show();

            DataSetFornecedor dsFornecedores = new DataSetFornecedor();
            dsFornecedores.Fornecedor.AddFornecedorRow("Fornecedor 1");
            dsFornecedores.Fornecedor.AddFornecedorRow("Fornecedor 2");
            dsFornecedores.Fornecedor.AddFornecedorRow("Fornecedor 3");
            dsFornecedores.Fornecedor.AddFornecedorRow("Fornecedor 4");

            FormRelatorio.ShowReport(
                "MultiRelatorios.ReportFornecedor.rdlc",
                true,
                new Dictionary<string, object>() { { "DataSetFornecedor", dsFornecedores.Fornecedor } });
        }

Muito mais organizado, não é mesmo? Com isso, ao invés de ficar criando um formulário para cada novo relatório, podemos simplesmente utilizar e evoluir o nosso “FormRelatorio“.

Concluindo

Neste artigo você aprendeu que não é uma boa prática criar um formulário para cada relatório da nossa aplicação. Ao invés disso, é melhor criarmos um formulário único que será utilizado para exibir todo e qualquer relatório disponível no nosso sistema.

Agora, conte para mim nos comentários: você já utiliza hoje em dia um formulário padrão para exibir todos os relatórios? Ou você não sabia desse detalhe e estava criando um formulário para cada relatório do seu sistema? Se a sua resposta for a segunda opção, ajuste o seu projeto agora mesmo para que ele tenha somente um formulário de exibição de relatórios, antes que a situação saia do controle!

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

The post Multi-relatórios no mesmo formulário com o Report Viewer appeared first on André Alves de Lima.


Viewing all articles
Browse latest Browse all 61