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

Trabalhando com múltiplas tabelas no Report Viewer através da expressão Lookup

$
0
0

Quem trabalha com o Report Viewer provavelmente já sabe que ele não permite a exibição de dados vindos de múltiplas tabelas em um único controle. Isso quer dizer que, se você quiser exibir dados de mais de uma tabela em um controle Tablix, você terá que partir para alguma alternativa.

A alternativa mais utilizada é a consolidação dos dados em uma única DataTable (ou classe) que servirá como fonte de dados para os nossos relatórios. Porém, essa não é a melhor das alternativas, uma vez que teremos que potencialmente construir DataSets e DataTables customizados para cada relatório do nosso sistema.

O que pouca gente conhece é que existe a expressão “Lookup” no Report Viewer, que nos permite justamente pegar informações de outras tabelas. No artigo de hoje eu vou mostrar para você como utilizar essa expressão. Você quer deixar os seus relatórios do Report Viewer mais simples? Então continue lendo e veja como a expressão “Lookup” pode simplificar consideravelmente os seus relatórios.

Entendendo o problema

Antes de apresentar a solução, vamos entender o problema? Para isso, vamos criar um exemplo onde temos que desenvolver um relatório que exibirá dados vindos de múltiplas tabelas. Temos inúmeros cenários onde isso se faz necessário, mas, para não complicarmos muito, preparei um exemplo bem simples para que vocês possam entender mais facilmente.

Imagine que a nossa tarefa seja gerar um relatório sobre uma entidade chamada “Pessoa” em um sistema de Recursos Humanos. Essa entidade, além das propriedades habituais, tem também uma ligação com a entidade “Empresa” (a pessoa trabalha em algum lugar) e outra ligação com a entidade “Cargo” (ela ocupa uma determinada posição nessa empresa).

Para simularmos essa estrutura, vamos começar criando um novo projeto do tipo “Windows Forms Application“. Dentro desse projeto, adicione um novo DataSet tipado (dando o nome de “DataSetPessoa“) com as seguintes tabelas, colunas e relacionamentos:

Aproveitando que temos um DataSet tipado, vamos dar um duplo clique para implementarmos um método que alimentará esse DataSet com alguns dados de exemplo. Obviamente, em um sistema “de verdade” você teria que ler esses dados do banco:

    // C#
    partial class DataSetPessoa
    {
        public void PreencherComDadosDeExemplo()
        {
            var abcdev = this.Empresa.AddEmpresaRow("abcdev", "AA Lima Dev EPP", "99.999.999/9999-99");
            var microsoft = this.Empresa.AddEmpresaRow("Microsoft", "Microsoft BR Ltda", "99.999.999/9999-99");
            var google = this.Empresa.AddEmpresaRow("Google", "Google Brasil S/A", "99.999.999/9999-99");

            var analista = this.Cargo.AddCargoRow("Analista de Sistemas", "XXX");
            var arquiteto = this.Cargo.AddCargoRow("Arquiteto de Sistemas", "YYY");
            var diretor = this.Cargo.AddCargoRow("Diretor Administrativo", "ZZZ");

            this.Pessoa.AddPessoaRow("Andre", "Lima", new System.DateTime(1984, 1, 1), abcdev, analista, "999.999.99-99");
            this.Pessoa.AddPessoaRow("Larissa", "Lima", new System.DateTime(1987, 2, 2), abcdev, diretor, "999.999.99-99");
            this.Pessoa.AddPessoaRow("Fulano", "de Tal", new System.DateTime(1978, 3, 3), microsoft, arquiteto, "999.999.99-99");
            this.Pessoa.AddPessoaRow("Paula", "Bellizia", new System.DateTime(1970, 4, 4), microsoft, diretor, "999.999.99-99");
            this.Pessoa.AddPessoaRow("Fabio", "Coelho", new System.DateTime(1968, 5, 5), google, diretor, "999.999.99-99");
        }
    }
' VB.NET
Partial Class DataSetPessoa
    Public Sub PreencherComDadosDeExemplo()
        Dim Abcdev = Me.Empresa.AddEmpresaRow("abcdev", "AA Lima Dev EPP", "99.999.999/9999-99")
        Dim Microsoft = Me.Empresa.AddEmpresaRow("Microsoft", "Microsoft BR Ltda", "99.999.999/9999-99")
        Dim Google = Me.Empresa.AddEmpresaRow("Google", "Google Brasil S/A", "99.999.999/9999-99")

        Dim Analista = Me.Cargo.AddCargoRow("Analista de Sistemas", "XXX")
        Dim Arquiteto = Me.Cargo.AddCargoRow("Arquiteto de Sistemas", "YYY")
        Dim Diretor = Me.Cargo.AddCargoRow("Diretor Administrativo", "ZZZ")

        Me.Pessoa.AddPessoaRow("Andre", "Lima", New System.DateTime(1984, 1, 1), Abcdev, Analista, "999.999.99-99")
        Me.Pessoa.AddPessoaRow("Larissa", "Lima", New System.DateTime(1987, 2, 2), Abcdev, Diretor, "999.999.99-99")
        Me.Pessoa.AddPessoaRow("Fulano", "de Tal", New System.DateTime(1978, 3, 3), Microsoft, Arquiteto, "999.999.99-99")
        Me.Pessoa.AddPessoaRow("Paula", "Bellizia", New System.DateTime(1970, 4, 4), Microsoft, Diretor, "999.999.99-99")
        Me.Pessoa.AddPessoaRow("Fabio", "Coelho", New System.DateTime(1968, 5, 5), Google, Diretor, "999.999.99-99")
    End Sub
End Class

E agora? Como poderíamos fazer para montarmos um relatório que lista as pessoas desse DataSet, porém, incluindo as informações da empresa onde ela trabalha e as informações do cargo que ela ocupa?

Primeira alternativa: juntando tudo em uma única tabela

A primeira alternativa para resolvermos essa situação (e a mais utilizada) é criarmos um novo DataSet (ou classe) juntando todas as colunas que queremos exibir no relatório em uma única tabela. Ou seja, no nosso caso, teríamos somente uma tabela com todas as informações da Pessoa, Empresa e Cargo.

Para implementarmos essa alternativa, vamos adicionar um segundo DataSet tipado no nosso projeto (dando o nome de “DataSetRelatorio“), que deverá conter a seguinte tabela:

Vamos também dar um duplo clique no DataSet para criarmos um método que receberá uma instância de “DataSetPessoa” e juntará tudo na tabela unificada:

    // C#
    partial class DataSetRelatorio
    {
        public DataSetRelatorio(DataSetPessoa dsPessoa)
        {
            foreach (var pessoa in dsPessoa.Pessoa)
            {
                this.Pessoa.AddPessoaRow(
                    pessoa.PessoaID,
                    pessoa.Nome,
                    pessoa.Sobrenome,
                    pessoa.DataNascimento,
                    pessoa.EmpresaID,
                    pessoa.CargoID,
                    pessoa.CPF,
                    pessoa.EmpresaRow.NomeFantasia,
                    pessoa.EmpresaRow.RazaoSocial,
                    pessoa.EmpresaRow.CNPJ,
                    pessoa.CargoRow.Nome,
                    pessoa.CargoRow.Descricao);
            }
        }
    }
' VB.NET
Partial Class DataSetRelatorio
    Public Sub DataSetRelatorio(DsPessoa As DataSetPessoa)
        For Each PessoaRow In DsPessoa.Pessoa
            Me.Pessoa.AddPessoaRow(
                    PessoaRow.PessoaID,
                    PessoaRow.Nome,
                    PessoaRow.Sobrenome,
                    PessoaRow.DataNascimento,
                    PessoaRow.EmpresaID,
                    PessoaRow.CargoID,
                    PessoaRow.CPF,
                    PessoaRow.EmpresaRow.NomeFantasia,
                    PessoaRow.EmpresaRow.RazaoSocial,
                    PessoaRow.EmpresaRow.CNPJ,
                    PessoaRow.CargoRow.Nome,
                    PessoaRow.CargoRow.Descricao)
        Next
    End Sub
End Class

Com esse DataSet em mãos, podemos simplesmente criar um novo relatório baseado nessa DataTable unificada. Vamos dar o nome de “RelatorioPessoa” para esse novo relatório:

Dentro desse relatório, vamos adicionar um componente do tipo “Table“. Quando fazemos isso, o Visual Studio automaticamente nos perguntará as informações sobre o DataSet que deverá alimentar essa tabela. Nessa janela, vamos dar o nome de “DataSetPessoa” para o DataSet que será criado e vamos escolher a tabela “Pessoa” do nosso “DataSetRelatorio“:

Em seguida, vamos arrastar cada uma das colunas do DataSet para dentro da tabela:

O resultado final deverá ficar parecido com a imagem abaixo:

Por fim, vamos até o nosso formulário, onde arrastaremos um controle visualizador do Report Viewer para dentro do formulário e escolheremos o relatório que acabamos de criar:

No code-behind do formulário, vamos criar os DataSets que serão passados para o relatório:

        // C#
        private void Form1_Load(object sender, EventArgs e)
        {
            var dsPessoa = new DataSetPessoa();
            dsPessoa.PreencherComDadosDeExemplo();
            var dsRelatorio = new DataSetRelatorio(dsPessoa);

            this.reportViewer1.LocalReport.DataSources.Clear();
            this.reportViewer1.LocalReport.DataSources.Add(new Microsoft.Reporting.WinForms.ReportDataSource("DataSetPessoa", (DataTable)dsRelatorio.Pessoa));
            this.reportViewer1.RefreshReport();
        }
    ' VB.NET
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim DsPessoa As New DataSetPessoa()
        DsPessoa.PreencherComDadosDeExemplo()
        Dim DsRelatorio As New DataSetRelatorio(DsPessoa)

        Me.ReportViewer1.LocalReport.DataSources.Clear()
        Me.ReportViewer1.LocalReport.DataSources.Add(New Microsoft.Reporting.WinForms.ReportDataSource("DataSetPessoa", DirectCast(DsRelatorio.Pessoa, DataTable)))
        Me.ReportViewer1.RefreshReport()
    End Sub

Pronto! Execute a aplicação e confira o resultado:

Obviamente o relatório poderia ser melhor formatado, mas, como esse não é o foco desse artigo, resolvi deixa-lo com a formatação padrão.

Alternativa mais simples: múltiplas tabelas + expressão Lookup

Como vimos na seção anterior, para exibirmos dados de múltiplas tabelas no Report Viewer, nós podemos criar um novo DataSet (ou classe) juntando todos os dados em uma só estrutura. Apesar de essa alternativa resolver o problema, muitas vezes ela acaba sendo um tanto quanto custosa. Imagine se o nosso sistema tiver diversos relatórios e todos eles tiverem que exibir dados de múltiplas tabelas? Teríamos que criar um DataSet novo para cada relatório, o que seria possível, mas, impraticável.

Uma alternativa mais simples seria trabalharmos com vários DataSets no mesmo relatório, sendo que um DataSet apontaria para a tabela “principal” (no nosso caso a tabela “Pessoa“) e os outros DataSets seriam as tabelas de “Lookup” (no nosso caso as tabelas “Empresa” e “Cargo“). Então, através da função “Lookup“, nós conseguimos pegar dados das tabelas de “Empresa” e “Cargo” no nosso relatório (seria a mesma ideia do PROCV ou VLOOKUP do Excel).

Para vermos como ficaria essa alternativa, vamos criar uma cópia do “RelatorioPessoa“, dando o nome de “RelatorioPessoaMultiplasTabelas“. Dentro desse relatório, vamos excluir o DataSet que tínhamos criado no relatório original (o “DataSetPessoa“) e vamos adicionar três novos DataSets, cada um apontando para uma tabela do nosso DataSetPessoa:

Em seguida, vamos alterar o DataSource da nossa tabela, de forma que ele aponte para o DataSet “Pessoa“:

E agora é que vem o segredo. Como é que conseguimos pegar os dados da Empresa, uma vez que o DataSet da tabela não tem essas informações? Simples, através da expressão Lookup! Por exemplo, para pegarmos o nome fantasia da empresa, a expressão ficaria assim:

=Lookup(Fields!EmpresaID.Value, Fields!EmpresaID.Value, Fields!NomeFantasia.Value, "Empresa")

O primeiro parâmetro dessa expressão deve ser o nome do campo na tabela de origem (campo “EmpresaID” da tabela “Pessoa“). Já o segundo parâmetro corresponde ao nome do campo na tabela destino (no nosso caso, “EmpresaID“, que é o nome do campo chave na tabela “Empresa“). Ou seja, esses dois primeiros parâmetros indicam os campos de relacionamento entre a tabela origem e a tabela destino.

Em seguida, o terceiro parâmetro deve conter o nome que você quer pegar na tabela de destino. Nesse caso, queremos pegar o campo “NomeFantasia“. Por fim, no último parâmetro nós temos que indicar o nome da tabela de lookup (nesse caso, “Empresa“).

Fácil, não? Veja só como fica a expressão para os outros campos:

' Razão social:
=Lookup(Fields!EmpresaID.Value, Fields!EmpresaID.Value, Fields!RazaoSocial.Value, "Empresa")
' CNPJ
=Lookup(Fields!EmpresaID.Value, Fields!EmpresaID.Value, Fields!CNPJ.Value, "Empresa")
' Nome do Cargo
=Lookup(Fields!CargoID.Value, Fields!CargoID.Value, Fields!Nome.Value, "Cargo")
' Descrição do Cargo
=Lookup(Fields!CargoID.Value, Fields!CargoID.Value, Fields!Descricao.Value, "Cargo")

Agora que já temos o nosso novo relatório, vamos criar um novo formulário para exibi-lo (Form2). Como fizemos no primeiro formulário, nós temos que adicionar um controle exibidor do Report Viewer, só que dessa vez nós selecionaremos o nosso novo relatório (“RelatorioPessoaMultiplasTabelas“). No code-behind, nós não temos mais que criar um DataSetRelatorio, mas sim, temos que passar cada uma das tabelas para o relatório em DataSources diferentes:

        // C#
        private void Form2_Load(object sender, EventArgs e)
        {
            var dsPessoa = new DataSetPessoa();
            dsPessoa.PreencherComDadosDeExemplo();

            this.reportViewer1.LocalReport.DataSources.Clear();
            this.reportViewer1.LocalReport.DataSources.Add(new Microsoft.Reporting.WinForms.ReportDataSource("Pessoa", (DataTable)dsPessoa.Pessoa));
            this.reportViewer1.LocalReport.DataSources.Add(new Microsoft.Reporting.WinForms.ReportDataSource("Empresa", (DataTable)dsPessoa.Empresa));
            this.reportViewer1.LocalReport.DataSources.Add(new Microsoft.Reporting.WinForms.ReportDataSource("Cargo", (DataTable)dsPessoa.Cargo));
            this.reportViewer1.RefreshReport();
        }
    ' VB.NET
    Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim DsPessoa = New DataSetPessoa()
        DsPessoa.PreencherComDadosDeExemplo()

        Me.ReportViewer1.LocalReport.DataSources.Clear()
        Me.ReportViewer1.LocalReport.DataSources.Add(New Microsoft.Reporting.WinForms.ReportDataSource("Pessoa", DirectCast(DsPessoa.Pessoa, DataTable)))
        Me.ReportViewer1.LocalReport.DataSources.Add(New Microsoft.Reporting.WinForms.ReportDataSource("Empresa", DirectCast(DsPessoa.Empresa, DataTable)))
        Me.ReportViewer1.LocalReport.DataSources.Add(New Microsoft.Reporting.WinForms.ReportDataSource("Cargo", DirectCast(DsPessoa.Cargo, DataTable)))
        Me.ReportViewer1.RefreshReport()
    End Sub

Por fim, vamos alterar o objeto de inicialização para que o nosso Form2 seja exibido (ao invés do Form1). Em projetos C#, fazemos isso no arquivo Program.cs:

Application.Run(new Form2());

Já no VB.NET, temos que alterar o “Startup Form” nas propriedades do projeto:

Pronto! Execute o projeto e veja que o resultado é idêntico ao primeiro relatório:

Concluindo

Quando estamos desenvolvendo relatórios para as nossas aplicações, não é tão difícil nos depararmos com uma situação em que precisamos de dados vindos de múltiplas tabelas. Como o Report Viewer não suporta a exibição de dados de mais de uma tabela no mesmo controle e também não tem o conceito de relacionamentos entre tabelas (como temos no Crystal Reports), a saída mais utilizada é a criação de um segundo DataSet (ou classe) onde todos os dados são consolidados em uma única DataTable.

Apesar dessa alternativa ser a mais utilizada, ela não é a mais ideal. O que pouca gente sabe é que nós podemos utilizar a expressão Lookup para pegarmos dados de outras tabelas no Report Viewer. Esse procedimento é muito mais simples do que termos que criar um DataSet consolidado para cada relatório.

No artigo de hoje você conferiu essas duas alternativas para a exibição de dados vindos de múltiplas tabelas no Report Viewer. Como você pode perceber, o resultado é idêntico, então, não pense duas vezes se você puder utilizar a expressão Lookup nos seus relatórios, que é muito mais prática.

E você, já passou por essa situação onde você tinha que exibir dados de múltiplas tabelas no Report Viewer? Se sim, como é que você resolveu? Você já conhecia a expressão Lookup? Conte-nos mais detalhes 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 Jake Przespo used under Creative Commons
https://www.flickr.com/photos/jakeprzespo/4566115233/

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Trabalhando com múltiplas tabelas no Report Viewer através da expressão Lookup appeared first on André Alves de Lima.


Apresentação DevWeek 2016 – Ferramentas gratuitas para geração de relatórios no .NET

$
0
0

Na noite de ontem eu participei do DevWeek 2016, evento 100% online e gratuito que está acontecendo durante toda essa semana, organizado pelo pessoal do Canal .NET.

A minha apresentação foi sobre ferramentas gratuitas para geração de relatórios no .NET. Apresentei o básico das ferramentas Crystal Reports e Report Viewer. Confira a gravação abaixo:

Links mencionados

Os principais links que eu mencionei durante a apresentação foram:

Suporte ao Crystal Reports no Visual Studio 2013

Aprenda a instalar o Crystal Reports no Visual Studio. Apesar do artigo ser voltado para o Visual Studio 2013, o processo é idêntico para o Visual Studio 2015, a única diferença é a versão que você terá que instalar.

Cadê o Report Viewer no Visual Studio 2015?

A Microsoft decidiu tirar o Report Viewer da instalação típica do Visual Studio a partir da versão 2015. Nesse artigo, veja como ativá-lo durante a instalação ou até mesmo se você já tiver instalado o Visual Studio sem ele.

Resolvendo o erro do Crystal Reports FileNotFoundException crdb_adoplus.dll

Existe um problema de compatibilidade do Crystal Reports a partir do .NET 4.0 que faz com que esse erro aconteça ao executar a aplicação. Esse erro pode ser facilmente corrigido com um ajuste no arquivo app.config. Nesse artigo eu mostro como fazer esse ajuste.

Qual é melhor – Crystal Reports ou Report Viewer?

Uma vez apresentadas as duas ferramentas, a dúvida que fica é: qual é o melhor? Qual eu devo utilizar em cada situação? Essas são as dúvidas que eu tento responder nesse artigo / vídeo.

Perguntas

Essas foram as perguntas que foram feitas no final da apresentação:

[Alexandre Rodrigues da Silva] Como saber como o relatório ficará em tempo de execução?

No Crystal Reports é fácil, uma vez que nós temos a aba “Preview” que mostra exatamente como o relatório ficará em tempo de execução. No Report Viewer, se estivermos trabalhando com relatórios server side (publicados no SQL Server Reporting Services), também temos essa aba “Preview” que mostra o resultado do relatório. Porém, para relatórios locais do Report Viewer, infelizmente não temos uma maneira de visualizar o resultado do relatório. A única opção é criarmos um formulário de testes e executar a aplicação.

[Vinicius Veras] Como gerar um relatório com 2 páginas / 2 vias?

Esse é um tema que eu quero demonstrar no ano que vem. Infelizmente, que eu saiba, o único jeito é no modo “gambiarra“. Basicamente você pode criar uma coluna virtual no seu Data Source (por exemplo “Via“). Aí você duplica os dados do DataSet / coleção, uma vez utilizando “Via” = 1 e outra vez utilizando “Via” = 2. Por fim, você agrupa o relatório por essa coluna e adiciona quebra de página entre as instâncias do grupo.

[Vinicius Takeushi] Só funciona com SQL Server?

Não, tanto o Crystal Reports quanto o Report Viewer funcionam com qualquer banco. Como você manda um DataSet ou coleção de objetos para o relatório, não interessa de qual banco as informações estão vindo. Inclusive na demonstração eu não utilizei nenhum banco (fiz com dados aleatórios em memória).

[Paulo Dias] O que o Crystal Reports tem que o Report Viewer não tem (e vice-versa)?

Veja o vídeo que linkei acima para um comparativo entre as duas ferramentas.

[Pietro NET] Qual tem melhor performance?

Sinceramente, não sei. Essa é uma análise que eu também quero fazer para publicar aqui no site. Eu particularmente acho o Report Viewer mais rápido na hora de carregar o relatório. O Crystal Reports tem um “lag” bem grande na hora do carregamento, principalmente a primeira vez que você está exibindo o relatório depois de reiniciar o computador. Mas, eu sinceramente não sei como as duas ferramentas se comportariam em um cenário onde o relatório seja extremamente complexo ou onde o relatório esteja sendo alimentado com muitos registros.

Baixe o projeto e o PPT

Como prometido, você pode baixar o projeto aqui (com o código tanto em C# quanto em VB.NET) e o PPT aqui.

Obrigado!

Antes de me despedir, quero agradecer imensamente o pessoal do Canal .NET pela oportunidade de ter participado no evento e também todo mundo que acompanhou o evento, tanto ao vivo quanto a gravação. Qualquer dúvida é só deixar aí nos comentários ou entrar em contato por e-mail. E aproveita para se inscrever na minha newsletter utilizando o formulário abaixo!

Até a próxima!

André Lima

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Apresentação DevWeek 2016 – Ferramentas gratuitas para geração de relatórios no .NET appeared first on André Alves de Lima.

Passando um DataSet não tipado para o Report Viewer

$
0
0

O grande problema ao criarmos relatórios do Report Viewer com DataSets tipados é que, caso nós utilizemos DataAdapters vinculados às nossas DataTables, existem grandes chances dos dados do relatório virem de um banco de dados incorreto quando executarmos a aplicação no computador dos nossos clientes. Isso pode ser facilmente contornado alterando manualmente a string de conexão no computador do cliente ou até mesmo alterando a string de conexão via código em tempo de execução.

Mas, que tal passarmos um DataSet não tipado para o Report Viewer? Dessa forma nós ficaríamos totalmente flexíveis na hora de carregarmos os dados dos nossos relatórios. Nós poderíamos, por exemplo, carregar os dados através de um TableAdapter ou DataReader. Poderíamos também carregar os dados de algum outro lugar que não fosse o banco de dados (um arquivo texto, uma planilha do Excel, etc).

No artigo de hoje eu vou mostrar como você pode alterar a string de conexão dos DataSets tipados em tempo de execução (caso você deseje trabalhar com DataSets tipados). Além disso, eu vou ensinar também como passar DataSets não tipados para o Report Viewer.

Criando o relatório com DataSet tipado ou classe

Infelizmente, as únicas maneiras (nativas) de criarmos relatórios no Report Viewer é através de um DataSet tipado ou classe (além das outras opções mais exóticas, como através de serviços ou listas do SharePoint). Dessa forma, mesmo que a gente decida passar um DataSet não tipado para o Report Viewer em tempo de execução, nós teremos que obrigatoriamente criar um DataSet tipado ou classe para conseguirmos desenhar a estrutura do relatório. Existe também uma gambiarra onde editamos o arquivo rdlc manualmente, mas esse truque eu vou deixar para um próximo artigo.

Dito isso, vamos começar o nosso projeto de exemplo criando um novo projeto do tipo “Windows Forms Application“. Poderia ser WPF ou poderia ser web e o resultado seria o mesmo, mas vamos trabalhar com Windows Forms para facilitar a demonstração.

Dentro desse projeto, vamos analisar as duas possibilidades que temos para desenharmos o nosso relatório: DataSet tipado ou classe. A primeira opção (DataSet tipado) é a mais óbvia. Vamos adicionar um novo DataSet tipado ao projeto, dando o nome de “DataSetPessoa“:

Dentro desse DataSet tipado, vamos adicionar uma nova DataTable, chamada “Pessoa“, contendo as colunas “Id“, “Nome” e “Sobrenome“, sendo que a coluna “Id” é auto-incremento e chave primária:

E com isso nós temos o DataSet que nós poderíamos utilizar para criar o nosso relatório. Porém, essa não é a sistemática que a maioria das pessoas utiliza na criação de DataSets tipados. O mais comum é, ao invés de criar as DataTables manualmente, os programadores acabam arrastando as tabelas de um banco de dados existente para dentro do DataSet. O problema disso é que a string de conexão fica gravada no arquivo app.config do projeto, e muitas pessoas têm dificuldade em mudar posteriormente essa string de conexão em tempo de execução, fazendo com que o relatório pegue os dados do banco errado.

Para entendermos esse cenário, vou criar um outro DataSet tipado (“DataSetPessoa2“) e, na janela “Server Explorer“, eu vou criar uma conexão com um banco de dados do Microsoft Access já existente (você pode baixar o arquivo mdb aqui). Esse banco já possui uma tabela chamada “Pessoa” com a estrutura que precisamos para o nosso relatório, então eu vou arrastar essa tabela para dentro do DataSet tipado:

O resultado disso tudo é uma DataTable contendo um DataAdapter atachado, que tem todas as informações necessárias para carregar os dados daquele banco que selecionamos no Server Explorer:

Por fim, a terceira maneira de termos uma estrutura de dados para desenharmos o nosso relatório é através de uma classe. Vamos, então, adicionar uma nova classe no nosso projeto, dando o nome de “Pessoa“:

    // C#
    public class Pessoa
    {
        public int Id { get; set; }
        public string Nome { get; set; }
        public string Sobrenome { get; set; }
    }
' VB.NET
Public Class Pessoa
    Public Property Id As Integer
    Public Property Nome As String
    Public Property Sobrenome As String
End Class

Nesse ponto, não esqueça de compilar o projeto, senão essa classe não será detectada pelo Report Viewer nos próximos passos.

É importante frisar que nós não precisamos de toda essa parafernalha no nosso projeto. Nós só temos que escolher uma das três opções que eu apresentei acima: ou DataSet tipado com a tabela criada manualmente, ou DataSet tipado com a tabela vindo de um banco de dados existente ou uma classe de dados. Não faz sentido utilizar mais de uma sistemática no mesmo projeto. Eu só fiz dessa forma nesse artigo para mostrar todas as possibilidades existentes.

Agora chegou a hora de, finalmente, criarmos o nosso relatório. Vamos adicionar um novo relatório do Report Viewer no nosso projeto, dando o nome de “RelatorioPessoa“:

Nesse relatório, vamos adicionar uma nova fonte de dados, clicando com o botão direito em “Datasets” e escolhendo a opção “Add Dataset“:

Na janela Dataset Properties, o Report Viewer automaticamente detectará os dois DataSets tipados que temos no nosso projeto (“DataSetPessoa” e “DataSetPessoa2“):

Se quiséssemos trabalhar com a classe de dados (ao invés dos DataSets tipados), teríamos que clicar em “New“, escolher a opção “Object” como tipo do DataSource e depois encontraríamos a classe “Pessoa” na lista de classes do projeto:

Porém, ao invés disso, vamos trabalhar com o modelo que a maioria das pessoas utiliza e que, infelizmente, é o modelo que traz mais problemas: o DataSet tipado que tem uma DataTable com adapter atachado (no nosso caso, o “DataSetPessoa2“):

Agora que já temos o DataSet no relatório, vamos adicionar uma tabela bem simples que listará as informações da tabela “Pessoa“:

Pronto! Esse será o relatório que utilizaremos no exemplo deste artigo. É claro que poderíamos trabalhar com uma estrutura bem mais complexa e um design bem mais detalhado, porém a ideia do artigo é mostrar o envio dos dados para o relatório, e não o relatório em si. Se você quiser dicas para criar relatórios mais complexos, dá uma olhada no meu histórico de artigos sobre o Report Viewer que tem bastante coisa interessante já publicada.

Alterando a string de conexão do DataSet tipado em tempo de execução

Com o relatório finalizado, vamos ajustar o formulário do nosso projeto para exibirmos o relatório com os seus respectivos dados. A primeira coisa que temos que fazer é adicionarmos um controle do Report Viewer no formulário, docka-lo (para que ele ocupe o espaço todo do formulário) e temos também que escolher o relatório que será exibido:

Como criamos o relatório apontando para o DataSet tipado que tinha um adapter atachado, ao escolhermos esse relatório no controle, o Visual Studio criará automaticamente no formulário uma instância do DataSet, um BindingSource e uma instância do Adapter:

E, se olharmos no code-behind do formulário, no evento “Load“, o Visual Studio já colocou o código para fazer o carregamento do DataSet utilizando o Adapter. E qual é o problema disso? O problema é que o Adapter utilizará a string de conexão que está armazenada no arquivo app.config da aplicação. Veja só como ficou a string de conexão no projeto que eu criei:

Essa string de conexão criada pelo Visual Studio está errada e, se eu tentar executar o projeto, veja só o erro que eu vou acabar recebendo:

Obviamente, na hora de fazermos o deployment desse projeto, esse caminho do arquivo será inválido também. E isso pode acontecer não só com o Microsoft Access, mas com qualquer banco de dados (quando trabalhamos com o SQL Server, o nome da instância pode ser diferente no cliente, por exemplo).

A solução nesse caso é alterarmos a string de conexão em tempo de execução. E como é que podemos fazer isso? É simples. Só precisamos abrir o arquivo de configuração (utilizando a classe ConfigurationManager), alteramos a string de conexão e salvamos o arquivo novamente. Porém, um detalhe importante é que essa classe fica no assembly System.Configuration, que não é referenciado por padrão quando criamos um novo projeto. Portanto, precisamos adicionar manualmente a referência para esse assembly:

Adicionada a referência, podemos utilizar a classe ConfigurationManager para alterar a nossa string de conexão. Veja como fica o código de forma que a string de conexão aponte para o arquivo Banco1.mdb no mesmo diretório da aplicação:

        // C#
        private void AlterarStringDeConexao()
        {
            var config = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.None);
            var connectionStrings = config.ConnectionStrings;
            foreach (System.Configuration.ConnectionStringSettings connectionString in connectionStrings.ConnectionStrings)
            {
                connectionString.ConnectionString = string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0}\\Banco1.mdb", Environment.CurrentDirectory);
            }
            config.Save(System.Configuration.ConfigurationSaveMode.Modified);
            System.Configuration.ConfigurationManager.RefreshSection("connectionStrings");
        }
    ' VB.NET
    Private Sub AlterarStringDeConexao()
        Dim Config = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.None)
        Dim ConnectionStrings = Config.ConnectionStrings
        For Each ConnectionString As System.Configuration.ConnectionStringSettings In ConnectionStrings.ConnectionStrings
            ConnectionString.ConnectionString = String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0}\Banco1.mdb", Environment.CurrentDirectory)
        Next
        Config.Save(System.Configuration.ConfigurationSaveMode.Modified)
        System.Configuration.ConfigurationManager.RefreshSection("connectionStrings")
    End Sub

Nota: obviamente, caso a sua aplicação utilize mais de uma string de conexão ao mesmo tempo, você teria que lidar com essa especificidade nesse método.

Agora nós só temos que adicionar a chamada para esse método antes do carregamento da DataTable:

        // C#
        private void Form1_Load(object sender, EventArgs e)
        {
            AlterarStringDeConexao();

            this.PessoaTableAdapter.Fill(this.DataSetPessoa2.Pessoa);

            this.reportViewer1.RefreshReport();
        }
    ' VB.NET
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        AlterarStringDeConexao()

        Me.PessoaTableAdapter.Fill(Me.DataSetPessoa2.Pessoa)

        Me.ReportViewer1.RefreshReport()
    End Sub

Ao executarmos novamente o projeto, veremos que os dados serão carregados corretamente através do arquivo mdb especificado na string de conexão:

Criando e passando um DataSet não tipado

Muito bem. Nós já vimos como criar o relatório com DataSet tipado (ligado ou não a um banco de dados via TableAdapter) e classe de dados. Já vimos também como carregar o relatório através de um DataSet tipado que contenha um Adapter, inclusive alterando a string de conexão em tempo de execução. Agora chegou a hora de vermos como podemos carregar esse relatório que criamos utilizando um DataSet não tipado.

Um DataSet não tipado é um DataSet criado diretamente via código. Para o caso do Report Viewer, nós nem precisamos de um DataSet em si, mas somente, uma DataTable (um DataSet seria mais ou menos um agrupamento de DataTables). Dessa forma, a primeira coisa que temos que fazer é criarmos uma DataTable com as respectivas colunas:

            // C#
            var dataTable = new DataTable();
            dataTable.Columns.Add("Id", typeof(int));
            dataTable.Columns.Add("Nome");
            dataTable.Columns.Add("Sobrenome");
        ' VB.NET
        Dim DataTable = New DataTable()
        DataTable.Columns.Add("Id", GetType(Integer))
        DataTable.Columns.Add("Nome")
        DataTable.Columns.Add("Sobrenome")

Nota: os nomes das colunas da DataTable devem bater exatamente com os nomes das colunas no DataSet do relatório, inclusive as letras maiúsculas e minúsculas.

Em seguida, temos que carregar essa tabela de alguma maneira. Num sistema “de verdade“, você teria que carregar os dados do banco de dados, provavelmente utilizando um TableAdapter ou DataReader. Como esse não é o foco do artigo (não importa de onde você esteja pegando os dados), eu vou simplesmente criar algumas linhas manualmente:

            // C#
            dataTable.Rows.Add(1, "André", "Lima");
            dataTable.Rows.Add(2, "Fulano", "de Tal");
            dataTable.Rows.Add(3, "Beltrano", "da Silva");
            dataTable.Rows.Add(4, "Zé", "Ninguém");
        ' VB.NET
        DataTable.Rows.Add(1, "André", "Lima")
        DataTable.Rows.Add(2, "Fulano", "de Tal")
        DataTable.Rows.Add(3, "Beltrano", "da Silva")
        DataTable.Rows.Add(4, "Zé", "Ninguém")

Por fim, a única coisa que está faltando é passarmos essa DataTable para o nosso relatório. Veja só como fazemos isso:

            // C#
            this.reportViewer1.LocalReport.DataSources.Clear();
            this.reportViewer1.LocalReport.DataSources.Add(new Microsoft.Reporting.WinForms.ReportDataSource("DataSetPessoa", dataTable));
        ' VB.NET
        Me.ReportViewer1.LocalReport.DataSources.Clear()
        Me.ReportViewer1.LocalReport.DataSources.Add(New Microsoft.Reporting.WinForms.ReportDataSource("DataSetPessoa", DataTable))

Atenção! O nome do DataSet (primeiro parâmetro do construtor da classe ReportDataSource) deve bater exatamente com o nome definido no DataSet dentro do relatório, inclusive letras maiúsculas e minúsculas.

Pronto! Execute o projeto e veja que o relatório será exibido corretamente. Aqui vai o resultado do código completo da criação da DataTable e carregamento do relatório:

        // C#
        private void Form1_Load(object sender, EventArgs e)
        {
            var dataTable = new DataTable();
            dataTable.Columns.Add("Id", typeof(int));
            dataTable.Columns.Add("Nome");
            dataTable.Columns.Add("Sobrenome");

            dataTable.Rows.Add(1, "André", "Lima");
            dataTable.Rows.Add(2, "Fulano", "de Tal");
            dataTable.Rows.Add(3, "Beltrano", "da Silva");
            dataTable.Rows.Add(4, "Zé", "Ninguém");

            this.reportViewer1.LocalReport.DataSources.Clear();
            this.reportViewer1.LocalReport.DataSources.Add(new Microsoft.Reporting.WinForms.ReportDataSource("DataSetPessoa", dataTable));

            this.reportViewer1.RefreshReport();
        }
    ' VB.NET
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim DataTable = New DataTable()
        DataTable.Columns.Add("Id", GetType(Integer))
        DataTable.Columns.Add("Nome")
        DataTable.Columns.Add("Sobrenome")

        DataTable.Rows.Add(1, "André", "Lima")
        DataTable.Rows.Add(2, "Fulano", "de Tal")
        DataTable.Rows.Add(3, "Beltrano", "da Silva")
        DataTable.Rows.Add(4, "Zé", "Ninguém")

        Me.ReportViewer1.LocalReport.DataSources.Clear()
        Me.ReportViewer1.LocalReport.DataSources.Add(New Microsoft.Reporting.WinForms.ReportDataSource("DataSetPessoa", DataTable))

        Me.ReportViewer1.RefreshReport()
    End Sub

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.

Concluindo

A principal dificuldade que os programadores enfrentam no desenvolvimento de relatórios com o Report Viewer é acertar no carregamento dos dados. Muitas vezes, ao utilizarmos DataSets tipados, a string de conexão acaba apontando para o lugar errado.

No artigo de hoje você aprendeu a alterar a string de conexão em tempo de execução (para o caso de você estar utilizando DataSets tipados com Adapters) e aprendeu também a passar um DataSet não tipado para o Report Viewer. Dessa forma você tem total flexibilidade na hora de carregar os dados dos seus relatórios.

O que achou? Gostou desse artigo? Escreva um comentário deixando a sua opinião e compartilhe esse artigo com algum amigo que possa se beneficiar desse aprendizado!

Até a próxima!

André Lima

Image by Juhan Sonin used under Creative Commons
https://www.flickr.com/photos/juhansonin/5135576565

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Passando um DataSet não tipado para o Report Viewer appeared first on André Alves de Lima.

Ativando o Report Viewer no Visual Studio 2015

$
0
0

Um dos artigos mais visualizados aqui no meu site é o artigo onde eu mostro como ativar o Report Viewer no Visual Studio 2015. Como algumas pessoas aprendem melhor com vídeo (ou preferem conteúdo em vídeo), resolvi aproveitar a popularidade desse tema para gravar um vídeo super rápido mostrando como ativar o Report Viewer no Visual Studio 2015. Confere aí:

E cadê o Report Viewer no Visual Studio 2017?

Como expliquei no vídeo, a Microsoft está mudando a estratégia de distribuição do Report Viewer a partir do Visual Studio 2017. A ideia é que o controle para utilização nos nossos projetos será distribuído via pacote do NuGet e a experiência de design de relatórios será distribuída através de uma extensão do Visual Studio. Eu detalhei tudo no artigo onde eu explico que a Microsoft não está descontinuando o Report Viewer.

Assine a minha newsletter

Antes de me despedir, convido você a inscrever-se na minha newsletter. Ao fazer isso, você terá acesso aos projetos de exemplo utilizados nos artigos, 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

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/

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Ativando o Report Viewer no Visual Studio 2015 appeared first on André Alves de Lima.

Ativando o Crystal Reports no Visual Studio 2015

$
0
0

No meu último vídeo eu mostrei como ativar o Report Viewer no Visual Studio 2015. Aproveitando essa onda de relatórios, no vídeo de hoje eu resolvi mostrar como ativar o Crystal Reports no Visual Studio 2015.

O Crystal Reports é uma ferramenta de geração de relatórios poderosíssima e super conhecida no mercado. Existe uma versão gratuita praticamente sem limitações e que pode ser instalada em conjunto com o Visual Studio (inclusive na edição Community!). Veja só como ativá-lo neste vídeo:

O procedimento é muito simples. Basta acessarmos a página de downloads do Crystal Reports para Visual Studio e baixarmos o “Support Pack” mais atual. A instalação é muito tranquila, no famoso estilo “next, next, finish“.

Na última etapa da instalação o instalador vai perguntar se você quer instalar a runtime do Crystal Reports (que é necessária para conseguirmos visualizar os relatórios em tempo de execução). Eu costumo pular essa etapa e instalar manualmente as runtimes (colunas “MSI 32 Bit” e “MSI 64 Bit” da página de downloads). Faço isso de forma manual, primeiro a 32 bits e depois a 64 bits, porque antigamente existia um bug que, se você instalasse primeiro a runtime 64 bits, você não conseguiria instalar a runtime 32 bits depois. Não sei se esse bug já foi corrigido, mas, para evitar problemas, eu continuo fazendo essa instalação manual.

E no Visual Studio 2017?

No momento da gravação desse vídeo (fevereiro de 2017), o Visual Studio 2017 ainda não era suportado. Porém, como a SAP já colocou uma informação na página de downloads falando que essa versão ainda não é suportada, acredito que com um próximo “Support Pack” eles adicionarão o suporte ao Visual Studio 2017. Tudo indica que o processo de instalação continuará o mesmo.

Assine a minha newsletter

Antes de me despedir, convido você a inscrever-se na minha newsletter. Ao fazer isso, você terá acesso aos projetos de exemplo utilizados nos artigos, 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

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/

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Ativando o Crystal Reports no Visual Studio 2015 appeared first on André Alves de Lima.

Como utilizar o Report Viewer no Visual Studio 2017?

$
0
0

Você está tentando utilizar o Report Viewer no Visual Studio 2017 e não está conseguindo? Já ativou o SQL Server Data Tools na instalação do Visual Studio e mesmo assim nada do Report Viewer aparecer? E agora, será que a Microsoft realmente descontinuou o Report Viewer?

Não se assuste, felizmente o Report Viewer ainda não foi descontinuado. O que acontece é que a Microsoft está mudando o modelo de distribuição do Report Viewer a partir do Visual Studio 2017. Eu até já falei sobre isso nesse outro artigo. A novidade é que a experiência de design de relatórios para o Visual Studio 2017 ficou pronta. Vamos ver como ficou o resultado?

Versão em vídeo

Esse assunto está quentíssimo, então eu resolvi gravar também esse tutorial em formato vídeo, que você confere abaixo:

O novo modelo de distribuição do Report Viewer

Mais uma vez a Microsoft alterou o modelo de distribuição do Report Viewer com o Visual Studio. Até o Visual Studio 2013 ele era instalado junto com a instalação típica do Visual Studio. Depois, a partir do Visual Studio 2015, nós precisávamos habilitar o SQL Server Data Tools na hora da instalação. Agora, com o Visual Studio 2017, ele foi totalmente removido da instalação do Visual Studio.

Eu já expliquei em detalhes o novo modelo de distribuição do Report Viewer no Visual Studio 2017 e os motivos da Microsoft ter feito essa alteração nesse outro artigo, mas, resumindo mais uma vez: a experiência de design dos relatórios será ativada através de uma extensão do Visual Studio (essa é a novidade do artigo de hoje) e o controle em si será distribuído através do NuGet.

Desenhando relatórios do Report Viewer no Visual Studio 2017

A grande novidade do artigo de hoje é que a extensão utilizada para ativarmos a experiência de design de relatórios do Report Viewer no Visual Studio 2017 ficou pronta. Com o Visual Studio 2017 instalado, se tentarmos adicionar um novo item dentro de um projeto, nós não encontraremos a categoria “Report” e tampouco encontraremos o item correspondente ao Report Viewer se fizermos uma pesquisa nos templates instalados:

E como é que podemos instalar a extensão que adiciona o Report Viewer? Simples! Uma opção é baixa-la diretamente no Visual Studio Marketplace, procurando pelo nome “Microsoft Rdlc Report Designer for Visual Studio“. A outra opção é abrirmos a janela de “Extensions and Updates” no Visual Studio:

Aí clicamos na categoria “Online“, procuramos por “rdlc” e instalamos o item “Microsoft Rdlc Report Designer for Visual Studio“:

Independente da opção que você escolher, a instalação será agendada para ser executada uma vez que todas as instâncias do Visual Studio sejam fechadas. Ao fechar todas as instâncias, essa janela será exibida:

A única coisa que temos que fazer nesse ponto é clicar em “Modify” e seguir as instruções do instalador. Uma vez concluída a instalação, se abrirmos o nosso projeto novamente e tentarmos adicionar um novo item, nós encontraremos os itens “Report” e “Report Wizard” dentro da categoria “Visual C# Items” (ou “Visual Basic Items“):

Nota: uma coisa que eu não gostei é que esses itens não foram organizados dentro de uma categoria separada. No Visual Studio 2015 eles eram separados na categoria “Reporting”. Mas, essa é somente a primeira versão. Quem sabe a Microsoft não melhora isso mais para frente.

Se você adicionar um novo item do tipo “Report” no seu projeto, você conseguirá desenhar os seus relatórios normalmente, da mesma forma que você conseguia fazer com o Visual Studio 2015. Aparentemente, o designer continua idêntico ao designer do Visual Studio 2015 (pelo menos essa foi a minha primeira impressão).

Controle do Report Viewer em projetos Windows Forms

No Visual Studio 2015, se quiséssemos adicionar o controle do Report Viewer nos nossos projetos, bastava arrastarmos o controle da caixa de ferramentas para dentro do formulário e pronto, missão cumprida! Porém, a partir do Visual Studio 2017, você não conseguirá encontrar o controle do Report Viewer na caixa de ferramentas. Isso acontece porque ele será distribuído via NuGet.

Dito isso, a primeira coisa que temos que fazer é adicionarmos a referência no nosso projeto. Para isso, abrimos a tela do NuGet, procuramos por “reportviewercontrol” e instalamos o item correspondente:

Em seguida, nós podemos adicionar um novo item na caixa de ferramentas apontando para a dll do Report Viewer que acabou de ser baixada. Fazemos isso clicando com o botão direito na área vazia da caixa de ferramentas e escolhendo a opção “Choose Items“:

Na janela “Choose Toolbox Items“, clicamos no botão “Browse“, navegamos até a pasta “packages” onde o Report Viewer foi baixado no nosso projeto e escolhemos o arquivo “Microsoft.ReportViewer.WinForms.dll“:

Feito isso, basta ativarmos o item “ReportViewer” e clicarmos em “OK” para que o controle do Report Viewer seja adicionado na nossa caixa de ferramentas.

A partir daqui a experiência continua como no Visual Studio 2015: basta arrastarmos o controle para dentro do nosso formulário e customizá-lo conforme precisarmos.

E no Web Forms?

O esquema para utilizarmos o novo controle do Report Viewer no Web Forms segue a mesma linha do Windows Forms. Precisamos adicionar o pacote do NuGet, só que dessa vez temos que prestar atenção para adicionarmos o pacote correto, referente do Web Forms:

Uma vez adicionada a referência, uma página web será aberta com um pequeno tutorial mostrando como adicionar o controle do Report Viewer no seu web form:

Você consegue acessar essa página diretamente no GitHub do Reporting Services, através deste link.

Em resumo, primeiramente você precisa adicionar uma referência à dll do Report Viewer no cabeçalho do seu web form:

<%@ Register assembly="Microsoft.ReportViewer.WebForms, Version=14.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" namespace="Microsoft.Reporting.WebForms" tagprefix="rsweb" %>

Em seguida, fazemos exatamente como estamos acostumados com a versão anterior do Report Viewer. Ou seja, adicionamos um ScriptManager e um controle do Report Viewer logo em seguida:

        <div>
            <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
            <rsweb:ReportViewer ID="ReportViewer1" runat="server" SizeToReportContent="True" />
        </div>

Por fim, no code-behind do web form, nós carregamos o relatório:

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                ReportViewer1.LocalReport.ReportPath = Server.MapPath("~/Report1.rdlc");
                ReportViewer1.LocalReport.Refresh();
            }
        }

O destaque aqui fica para o novo controle desenvolvido pelo time do Reporting Services, escrito totalmente em HTML5:

E no MVC?

Não existe suporte nativo ao Report Viewer no MVC. Dito isso, uma opção que nós temos para contornar essa limitação é adicionarmos um web form no nosso projeto MVC e trabalharmos como se estivéssemos em um projeto Web Forms puro.

Obviamente essa opção não é das melhores, uma vez que perdemos toda a separação de camadas que temos no MVC, com models, views e controllers. Foi pensando nisso que algumas pessoas já desenvolveram bibliotecas que implementam uma certa gambiarra por trás dos panos que possibilita a utilização do Report Viewer no estilo de desenvolvimento do MVC.

A biblioteca que eu costumo utilizar para exibir relatórios do Report Viewer no MVC é a “ReportViewer for MVC“. Se você se interessar por esse assunto, eu já expliquei como utilizá-la neste outro artigo. O problema é que essa biblioteca não tem sido mais atualizada e, por consequência, muito provavelmente não será atualizada para a versão mais nova do Report Viewer.

O meu plano é copiar essa biblioteca para o GitHub e atualizá-la para que ela aponte para essa versão mais nova do Report Viewer. Com isso eu vou conseguir também corrigir uns bugs dessa biblioteca relacionados ao carregamento de sub-relatórios (que você pode encontrar mais informações aqui).

Assim que eu conseguir fazer isso, eu volto aqui e edito esse post com mais informações.

E no .NET Core?

Até o momento, a Microsoft ainda não se pronunciou sobre uma possível implementação do Report Viewer que seja compatível com o .NET Core. Se você tentar adicionar a referência do Report Viewer via NuGet em um projeto .NET Core, você receberá um erro:

Porém, temos várias pessoas da comunidade discutindo sobre esse assunto nessa issue no GitHub do ASP.NET. Vale a pena acompanhar essa issue para ficar por dentro das novidades.

Concluindo

Com o lançamento de cada edição nova do Visual Studio surge aquela dúvida cruel para desenvolvedores de relatórios: será que a Microsoft descontinuou o Report Viewer? Para a nossa sorte, esse dia ainda não chegou.

Apesar do susto que tivemos com o Report Viewer não aparecendo no Visual Studio 2017 ao tentarmos adicioná-lo seguindo os mesmos passos do Visual Studio 2015, não precisamos ficar preocupados. O que aconteceu é que a Microsoft mudou completamente o modelo de distribuição do Report Viewer a partir do Visual Studio 2017, disponibilizando a experiência de design por meio de uma extensão e o controle através do NuGet.

No artigo de hoje você aprendeu todos os passos necessários para desenhar relatórios do Report Viewer no Visual Studio 2017, bem como a utilização do seu novo controle em projetos Windows Forms e Web Forms, além de uma visão da utilização no ASP.NET MVC e .NET Core.

Agora é seguir essas instruções e continuar desenvolvendo os nossos relatórios para satisfazer os nossos clientes. Aproveita e dá uma olhada na categoria do Report Viewer aqui do site para encontrar diversos outros tutoriais sobre essa ferramenta!

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

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Como utilizar o Report Viewer no Visual Studio 2017? appeared first on André Alves de Lima.

Trabalhando com o Report Viewer no MVC

$
0
0

O Report Viewer só tem suporte nativo ao Windows Forms e Web Forms, ou seja, quem trabalha com outras plataformas (como WPF ou MVC) precisa fazer alguns ajustes para poder utilizá-lo nos seus projetos. No caso do WPF, é só adicionar um WindowsFormsHost com o controle do Report Viewer dentro, como eu mostrei neste artigo. Já no ASP.NET MVC, ou adicionamos um WebForm (não recomendado) ou utilizamos uma biblioteca que possibilita a criação dos relatórios no “estilo MVC” de desenvolver.

Eu já escrevi um artigo mostrando como utilizar o Report Viewer no ASP.NET MVC, onde eu mostro as duas modalidades mencionadas acima. Devido à popularidade desse artigo, eu resolvi fazer uma versão em vídeo explorando um pouco mais a ideia da utilização da biblioteca “ReportViewerForMVC“. No vídeo eu mostro também um problema que temos ao utilizá-la com sub-relatórios. Confere aí:

Biblioteca ReportViewerForMVC

A biblioteca que podemos utilizar para trabalharmos com o Report Viewer no MVC (sem termos que adicionar um WebForm manualmente) é a “ReportViewerForMVC“. Como você pode reparar no site da biblioteca no CodePlex, ela não tem sido atualizada há um bom tempo. Porém, ela funciona bem com a versão 11 do Report Viewer, então ela acaba dando conta do recado.

Para adicionarmos uma referência a essa biblioteca no nosso projeto, nós utilizamos o NuGet. Basta procurarmos por “ReportViewerForMVC” na janela de gerenciamento de pacotes do NuGet ou digitarmos “Install-Package ReportViewerForMVC” no Package Manager Console:

Essa biblioteca adicionará a referência às dlls “Microsoft.ReportViewer.WebForms” e “ReportViewerForMvc“.

Outras referências necessárias

Em computadores que tenham a runtime do Report Viewer instalada, somente a referência à biblioteca já é o suficiente para que o nosso projeto funcione. Porém, para o caso em que a versão correta da runtime do Report Viewer não estiver instalada, algumas outras referências serão necessárias.

Por segurança, eu recomendo que você adicione pelo NuGet as referências às bibliotecas “MicrosoftReportViewerWebForms” e “Microsoft.SqlServer.Types” (versão 11.0.0):

O código do Controller

Uma vez adicionadas todas as referências necessárias, vamos partir para a criação do código do nosso Controller. Adicione um novo Controller vazio do MVC na pasta “Controllers” para que possamos fazer essa implementação.

A ideia é muito simples. Primeiramente nós temos que carregar os dados da nossa fonte de dados e armazená-los em um DataSet ou coleção. Em seguida, nós criamos uma instância da classe “Microsoft.Reporting.WebForms.ReportViewer” e configuramos algumas propriedades (como caminho do relatório e sua fonte de dados). Por fim, nós retornamos essa instância de “ReportViewer” através da ViewBag.

Veja só este exemplo:

        // C#
        public ActionResult Index()
        {
            var ds = ObterDados();

            var viewer = new Microsoft.Reporting.WebForms.ReportViewer();
            viewer.ProcessingMode = Microsoft.Reporting.WebForms.ProcessingMode.Local;
            viewer.LocalReport.ReportPath = Request.MapPath(Request.ApplicationPath) + @"CaminhoDoSeuRelatorio.rdlc";
            viewer.LocalReport.DataSources.Add(new Microsoft.Reporting.WebForms.ReportDataSource("NomeDoDataSetNoRelatorio", (System.Data.DataTable)ds.NomeDaDataTable));

            ViewBag.ReportViewer = viewer;

            return View();
        }
            ' VB.NET
            Dim Ds = ObterDados()

            Dim Viewer = New Microsoft.Reporting.WebForms.ReportViewer()
            Viewer.ProcessingMode = Microsoft.Reporting.WebForms.ProcessingMode.Local
            Viewer.LocalReport.ReportPath = Request.MapPath(Request.ApplicationPath) + "CaminhoDoSeuRelatorio.rdlc"
            Viewer.LocalReport.DataSources.Add(New Microsoft.Reporting.WebForms.ReportDataSource("NomeDoDataSetNoRelatorio", DirectCast(Ds.NomeDaDataTable, System.Data.DataTable)))

            ViewBag.ReportViewer = Viewer

            Return View()

E como fica a View?

Com o Controller em mãos, podemos partir para a criação da nossa View. O código dela é muito simples. Primeiramente nós temos que adicionar uma referência à biblioteca “ReportViewerForMvc” (com uma cláusula “using” no início da View). Adicionada essa referência, nós teremos alguns métodos extras à nossa disposição, como o “Html.ReportViewer“. Ao chamarmos esse método passando a instância do ReportViewer da ViewBag, o relatório será renderizado naquele local:

<!-- C# -->
@using ReportViewerForMvc;

@{
    ViewBag.Title = "Index";
}

<h2>Relatório</h2>

@Html.ReportViewer(ViewBag.ReportViewer as Microsoft.Reporting.WebForms.ReportViewer)
<!-- VB.NET -->
@Imports ReportViewerForMvc

@Code
    ViewData("Title") = "Index"
End Code

<h2>Index</h2>

@Html.ReportViewer(DirectCast(ViewBag.ReportViewer, Microsoft.Reporting.WebForms.ReportViewer))

Execute o projeto e veja o resultado:

Ajuste automático do tamanho do controle

Se observarmos o resultado apresentado na imagem acima, veremos que o controle está com um tamanho fixo (o tamanho padrão). No controle do Report Viewer web, temos a possibilidade de configurarmos um tamanho dinâmico, ou seja, o controle será automaticamente redimensionado dependendo do tamanho do relatório.

Para atingirmos esse resultado, temos que alterar a propriedade “SizeToReportContent” para verdadeiro, além de configurarmos o Width e Height de forma que eles ocupem 100% da área disponível na View. Coloque este código antes de retornar o controle para a ViewBag e veja a diferença:

            // C#
            viewer.SizeToReportContent = true;
            viewer.Width = System.Web.UI.WebControls.Unit.Percentage(100);
            viewer.Height = System.Web.UI.WebControls.Unit.Percentage(100);
            ' VB.NET
            Viewer.SizeToReportContent = True
            Viewer.Width = System.Web.UI.WebControls.Unit.Percentage(100)
            Viewer.Height = System.Web.UI.WebControls.Unit.Percentage(100)

Problemas com sub-relatórios

A biblioteca Report Viewer for MVC funciona muito bem até o momento em que tivermos que trabalhar com sub-relatórios. Para exibirmos um relatório que tenha sub-relatório, o código do Controller ficaria assim:

        // C#
        DataSet ds;

        public ActionResult Index()
        {
            ds = ObterDados();

            var viewer = new Microsoft.Reporting.WebForms.ReportViewer();
            viewer.ProcessingMode = Microsoft.Reporting.WebForms.ProcessingMode.Local;
            viewer.LocalReport.ReportPath = Request.MapPath(Request.ApplicationPath) + @"CaminhoDoSeuRelatorio.rdlc";
            viewer.LocalReport.DataSources.Add(new Microsoft.Reporting.WebForms.ReportDataSource("NomeDoDataSetNoRelatorio", (System.Data.DataTable)ds.NomeDaDataTable));
            viewer.LocalReport.SubreportProcessing += LocalReport_SubreportProcessing;

            ViewBag.ReportViewer = viewer;

            return View();
        }

        private void LocalReport_SubreportProcessing(object sender, Microsoft.Reporting.WebForms.SubreportProcessingEventArgs e)
        {
            e.DataSources.Add(new Microsoft.Reporting.WebForms.ReportDataSource("NomeDoDataSetNoSubRelatorio", (System.Data.DataTable)ds.NomeDaDataTableDetalhe));
        }
        ' VB.NET
        Private Ds As DataSet

        Public Function Index() As ActionResult
            Ds = ObterDados()

            Dim Viewer = New Microsoft.Reporting.WebForms.ReportViewer()
            Viewer.ProcessingMode = Microsoft.Reporting.WebForms.ProcessingMode.Local
            Viewer.LocalReport.ReportPath = Request.MapPath(Request.ApplicationPath) + "CaminhoDoSeuRelatorio.rdlc"
            Viewer.LocalReport.DataSources.Add(New Microsoft.Reporting.WebForms.ReportDataSource("NomeDoDataSetNoRelatorio", DirectCast(Ds.NomeDaDataTable, System.Data.DataTable)))
            AddHandler Viewer.LocalReport.SubreportProcessing, AddressOf LocalReport_SubreportProcessing

            Viewer.SizeToReportContent = True
            Viewer.Width = System.Web.UI.WebControls.Unit.Percentage(100)
            Viewer.Height = System.Web.UI.WebControls.Unit.Percentage(100)

            ViewBag.ReportViewer = Viewer

            Return View()
        End Function

        Private Sub LocalReport_SubreportProcessing(sender As Object, e As Microsoft.Reporting.WebForms.SubreportProcessingEventArgs)
            e.DataSources.Add(New Microsoft.Reporting.WebForms.ReportDataSource("NomeDoDataSetNoSubRelatorio", DirectCast(Ds.NomeDaDataTableDetalhe, System.Data.DataTable)))
        End Sub

Porém, se testarmos esse cenário com um breakpoint no evento “SubReportProcessing“, veremos que ele não será disparado. Isso acontece porque a biblioteca tem um bug que evita o disparo desse evento. Existe até uma “issue” criada no site da biblioteca falando sobre esse problema.

No link acima você pode notar que eu respondi aquela “issue” com a correção necessária para que os sub-relatórios funcionem. Eu fiz essa correção, recompilei a biblioteca e você pode baixar a versão corrigida aqui. Substitua essa dll na pasta “packages” e na pasta “Bin” do seu projeto para que os sub-relatórios funcionem corretamente. E acompanhe este repositório no meu GitHub, onde eu pretendo dar manutenção nessa biblioteca e disponibilizar atualizações.

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!

André Lima

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/

The post Trabalhando com o Report Viewer no MVC appeared first on André Alves de Lima.

Publicando sites com Report Viewer no Azure

$
0
0

Uma dúvida que eu recebo com uma certa frequência tanto por e-mail quanto através dos comentários aqui do site é: como fazer para publicar sites que utilizam o Report Viewer no Azure? No computador de desenvolvimento tudo funciona perfeitamente, porém, quando o site é enviado para o servidor, ele não funciona. O que fazer? Isso é o que eu vou mostrar para você no vídeo de hoje:

O primeiro erro genérico

Se publicarmos um site que utilize Report Viewer com as configurações padrão, nós receberemos um erro bem genérico ao tentarmos acessá-lo no nosso servidor:

Essa mensagem de erro não ajuda em nada, porque ela não fala exatamente qual é o motivo do site não estar sendo carregado. Para obtermos uma mensagem mais detalhada de erro, nós temos que desligar os erros customizados no nosso arquivo web.config, justamente como a mensagem de erro acima nos explicou:

Ao fazermos isso, nós receberemos uma mensagem de erro que faz mais sentido:

Nota: não esqueça de remover essa linha do seu web.config antes de fazer o deploy final do seu site! Com essa linha ativada, o usuário poderia receber informações que ele não deveria ficar sabendo, como mensagens detalhadas de exceções, stack traces, caminhos de arquivos, etc.

Adicionando as referências necessárias

Como podemos perceber na mensagem de erro acima, a dll Microsoft.ReportViewer.Common está faltando. Isso porque, por padrão, ao adicionarmos um controle do Report Viewer no projeto, o Visual Studio só adiciona a referência para a dll Microsoft.ReportViewer.WebForms. No computador de desenvolvimento o projeto funciona sem problemas porque nós temos a runtime do Report Viewer instalada. Porém, ao publicarmos no servidor (que não terá a runtime do Report Viewer instalada), ele não conseguirá encontrar as outras dlls do Report Viewer.

Para resolver esse problema, nós temos que adicionar manualmente as referências para as seguintes dlls no nosso projeto:

– Microsoft.ReportViewer.Common
– Microsoft.ReportViewer.ProcessingObjectModel

Você consegue encontrar essas dlls no GAC, que fica na pasta “C:\Windows\assembly\GAC_MSIL“. Só tome cuidado para adicionar a referência da versão correta do Report Viewer! Confira a versão que foi adicionada da dll Microsoft.ReportViewer.WebForms e utilize a mesma versão na hora de adicionar as outras referências.

Uma vez adicionadas as referências, confira se elas estão configuradas para serem copiadas no diretório da aplicação (Copy Local = True):

Não esqueça do arquivo rdlc!

Com as referências adicionadas, nós conseguiremos carregar o web site normalmente. Porém, pode ser que o arquivo rdlc esteja faltando no seu deployment também. Se esse for o caso, você receberá uma mensagem de erro parecida com esta:

Para corrigir esse problema, configure a opção “Copy to Output Directory” como “Copy always” nos seus arquivos rdlc:

Ao fazer isso, os arquivos rdlc serão copiados na pasta “bin” do seu web site. Na hora de carregar os relatórios, não esqueça de carrega-los da subpasta “bin” também. Exemplo:

SeuReportViewer.LocalReport.ReportPath = MapPath("bin\\SeuRelatorio.rdlc");

Eu precisso da dll Data Visualization?

Se você estiver trabalhando com gráficos nos seus relatórios (ou se você estiver planejando adicionar gráficos nos seus relatórios), você precisará adicionar também a referência à dll Microsoft.ReportViewer.DataVisualization. Siga os mesmos passos apresentados anteriormente para adicionar mais essa referência (encontre a dll no GAC e adicione a referência no projeto).

Concluindo

No vídeo de hoje você conferiu como fazer a distribuição de web sites que utilizem o Report Viewer no Azure. Esses mesmos passos são válidos para qualquer outro servidor que não tenha a runtime do Report Viewer instalada. Basta adicionarmos as referências de todas as dlls do Report Viewer no nosso projeto, configurá-las como “Copy Local” e pronto! Nosso web site funcionará tanto no computador de desenvolvimento quanto no servidor.

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

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/

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Publicando sites com Report Viewer no Azure appeared first on André Alves de Lima.


Trabalhando com drillthrough no Report Viewer

$
0
0

Ao construirmos uma aplicação que possua relatórios, muito provavelmente essa aplicação terá múltiplos relatórios (e não somente um). Uma funcionalidade que podemos adicionar nos nossos relatórios para melhorar a experiência do usuário é a navegação entre eles, diretamente no controle visualizador (sem ter que ficar fechando e abrindo formulários). No Report Viewer, isso é possível através do conceito de drillthrough.

O drillthrough é normalmente utilizado para explorarmos detalhes das linhas de um relatório (daí o nome drillthrough = “perfurar“). Por exemplo, se tivermos um relatório com uma listagem, nós podemos configurar um evento de clique nas linhas do relatório, que abrirá um outro relatório com dados mais detalhados daquela linha. Porém, nós não precisamos necessariamente utilizar essa funcionalidade para detalharmos uma linha, nós podemos simplesmente configurar uma navegação entre relatórios que não tenham nenhuma relação entre si.

No vídeo de hoje eu mostro para você como implementar o drillthrough no Report Viewer para fazermos a navegação entre relatórios:

Navegação entre relatórios independentes

Configurar uma navegação entre relatórios que não tenham relação entre si é algo muito simples de ser feito no Report Viewer. Basta abrirmos a janela de propriedades do TextBox que será o link para o outro relatório (pode ser qualquer outro tipo de controle também) e, na aba “Action“, nós configuramos o nome do relatório que deverá ser aberto (note que nós não devemos indicar a extensão “rdlc” no nome do relatório!):

Além disso, nós temos que passar de alguma forma os dados do segundo relatório que deverá ser aberto. Afinal de contas, como é que o Report Viewer poderia saber de onde pegar os dados, não é mesmo? O evento que temos que implementar para enviarmos os dados do segundo relatório é o evento chamado “Drillthrough“:

Nesse evento, nós passamos os dados do relatório através do método DataSources.Add:

        // C#
        private void reportViewer1_Drillthrough(object sender, Microsoft.Reporting.WinForms.DrillthroughEventArgs e)
        {
            var localReport = (Microsoft.Reporting.WinForms.LocalReport)e.Report;
            localReport.DataSources.Clear();

            if (e.ReportPath.Contains("RelatorioFornecedor"))
            {
                localReport.DataSources.Add(new Microsoft.Reporting.WinForms.ReportDataSource("DataSetRelatorio", (DataTable)ds.Fornecedor));
            }
        }
    ' VB.NET
    Private Sub ReportViewer1_Drillthrough(sender As Object, e As Microsoft.Reporting.WinForms.DrillthroughEventArgs) Handles ReportViewer1.Drillthrough
        Dim LocalReport = DirectCast(e.Report, Microsoft.Reporting.WinForms.LocalReport)
        LocalReport.DataSources.Clear()

        If e.ReportPath.Contains("RelatorioFornecedor") Then
            LocalReport.DataSources.Add(New Microsoft.Reporting.WinForms.ReportDataSource("DataSetRelatorio", DirectCast(Ds.Fornecedor, DataTable)))
        End If
    End Sub

Note que nós conseguimos avaliar o conteúdo da propriedade “ReportPath” para detectarmos qual relatório está sendo carregado. Isso é muito útil caso nós tenhamos mais de um drillthrough no mesmo relatório, apontando para destinos diferentes.

Navegação entre relatórios dependentes

A única diferença na navegação entre relatórios dependentes é que nós temos que, de alguma maneira, ligar o relatório pai com o relatório filho. Por exemplo, se nós tivermos uma listagem de clientes e quisermos que um outro relatório com as suas transações seja aberto ao clicarmos no ID do cliente, nós temos que criar um parâmetro no relatório de transações:

Em seguida, nas propriedades do Tablix, vamos configurar um filtro pelo ID do cliente, utilizando o valor do parâmetro:

Por fim, na hora de configurarmos a navegação para o relatório de transações, nós passamos o ID do cliente selecionado como valor do parâmetro “ClienteID” no relatório destino:

Pronto! E com isso nós configuramos a navegação entre o relatório de clientes e o relatório de transações do cliente, que será devidamente filtrado dependendo do cliente que for clicado pelo usuário. Só não esqueça de ajustar o código do evento “Drillthrough” de forma que os dados sejam passados para o relatório de transações também:

        // C#
        private void reportViewer1_Drillthrough(object sender, Microsoft.Reporting.WinForms.DrillthroughEventArgs e)
        {
            var localReport = (Microsoft.Reporting.WinForms.LocalReport)e.Report;
            localReport.DataSources.Clear();

            if (e.ReportPath.Contains("RelatorioFornecedor"))
            {
                localReport.DataSources.Add(new Microsoft.Reporting.WinForms.ReportDataSource("DataSetRelatorio", (DataTable)ds.Fornecedor));
            }
            else if (e.ReportPath.Contains("RelatorioTransacao"))
            {
                localReport.DataSources.Add(new Microsoft.Reporting.WinForms.ReportDataSource("DataSetRelatorio", (DataTable)ds.Transacao));
            }
        }
    ' VB.NET
    Private Sub ReportViewer1_Drillthrough(sender As Object, e As Microsoft.Reporting.WinForms.DrillthroughEventArgs) Handles ReportViewer1.Drillthrough
        Dim LocalReport = DirectCast(e.Report, Microsoft.Reporting.WinForms.LocalReport)
        LocalReport.DataSources.Clear()

        If e.ReportPath.Contains("RelatorioFornecedor") Then
            LocalReport.DataSources.Add(New Microsoft.Reporting.WinForms.ReportDataSource("DataSetRelatorio", DirectCast(Ds.Fornecedor, DataTable)))
        ElseIf e.ReportPath.Contains("RelatorioTransacao") Then
            LocalReport.DataSources.Add(New Microsoft.Reporting.WinForms.ReportDataSource("DataSetRelatorio", DirectCast(Ds.Transacao, DataTable)))
        End If
    End Sub

Escondendo botões de ação no modo impressão

Uma última melhoria que podemos fazer nesse exemplo é escondermos o TextBox que faz a abertura do relatório de fornecedores caso estivermos em modo impressão (ou exportação). Afinal, não faz sentido exibir esse TextBox na impressão ou exportação, uma vez que ele só serve como um link entre o relatório de clientes e o relatório de fornecedores.

Para fazermos isso, nós temos que adicionar uma expressão na propriedade “Hidden” desse TextBox, de maneira que ele seja escondido quando não estivermos no modo interativo:

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.

Concluindo

A funcionalidade de drillthrough do Report Viewer pode ser utilizada para adicionarmos navegação entre os relatórios da nossa aplicação. Ao utilizá-la, o usuário poderá navegar entre relatórios sem ter que ficar abrindo janelas diferentes. Essa é uma funcionalidade muito interessante que nós podemos adicionar nas nossas aplicações para melhorarmos a experiência do usuário.

Você já conhecia essa funcionalidade do Report Viewer? Já implementou nas suas aplicações? Deu tudo certo? Quais foram os problemas (ou melhor, desafios) que você encontrou ao utilizar drillthrough no Report Viewer? Conte-nos mais detalhes na caixa de comentários!

Até a próxima!

André Lima

Photo by Peter Shanks used under Creative Commons
https://pixabay.com/en/startup-start-up-notebooks-creative-593327/

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

Song Rocket Power Kevin MacLeod (incompetech.com)
Licensed under Creative Commons: By Attribution 3.0 License
http://creativecommons.org/licenses/by/3.0/

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Trabalhando com drillthrough no Report Viewer appeared first on André Alves de Lima.

Trabalhando com parâmetros no Report Viewer

$
0
0

Uma grande dificuldade que muitas pessoas acabam passando ao trabalhar com o Report Viewer é a questão de passagem de parâmetros. É através deles que nós conseguimos passar valores estáticos para os nossos relatórios. No vídeo de hoje eu quero acabar com esse problema de uma vez por todas. Você vai conferir todos os segredos para trabalhar com parâmetros no Report Viewer de forma efetiva. Confira:

Parâmetros para conteúdos estáticos

A principal razão para utilizarmos parâmetros em um relatório é para passarmos algum conteúdo estático que não faça parte do DataSet. Por exemplo, em uma aplicação “multi-empresa“, talvez faça sentido passar o nome da empresa para exibirmos em algum lugar do relatório, ou até mesmo o caminho do logotipo da empresa para exibirmos no cabeçalho do relatório.

Para criarmos parâmetros no nosso relatório do Report Viewer, basta clicarmos com o botão direito no item “Parameters” na janela “Report Data” e, em seguida, escolhemos a opção “Add Parameter“:

Na janela que se abre, escolhemos um nome e o tipo do parâmetro:

Com o parâmetro criado, para utilizarmos o seu valor dentro do relatório, basta arrastá-lo da janela “Report Data” para dentro do relatório:

Além de utilizarmos o valor do parâmetro em um TextBox, nós podemos também utilizá-lo em expressões (para configurar o caminho de uma imagem, por exemplo):

Para passarmos um valor para o nosso parâmetro, nós utilizamos o método “SetParameters“, que deve ser chamado antes de “RefreshReport“:

            // C#
            this.reportViewer1.LocalReport.SetParameters(new Microsoft.Reporting.WinForms.ReportParameter("Empresa", "Microsoft"));
            this.reportViewer1.RefreshReport();
        ' VB.NET
        Me.ReportViewer1.LocalReport.SetParameters(New Microsoft.Reporting.WinForms.ReportParameter("Empresa", "Microsoft"))
        Me.ReportViewer1.RefreshReport()

Parâmetros obrigatórios e opcionais

Se configurarmos um parâmetro como obrigatório sem valor padrão e não passarmos um valor para ele através do método “SetParameters“, nós receberemos um erro:

Para configurarmos um parâmetro como não obrigatório, nós temos que marcar as opções “Allow blank value” e/ou “Allow null value“:

Configurando um valor padrão para o parâmetro

Uma outra opção bem interessante que nós podemos configurar nos parâmetros do Report Viewer são os valores padrão. Dessa forma, se não passarmos nenhum valor para o parâmetro, ele assumirá o valor padrão que definimos no relatório.

Para configurarmos valores padrão para um parâmetro do Report Viewer, nós utilizamos a tab “Default Values“:

Cuidado com as letras maiúsculas e minúsculas!

Um cuidado muito importante que temos que ter na hora de passarmos os valores para os nossos parâmetros é que o Report Viewer diferencia maiúsculas e minúsculas. Ou seja, se definirmos o nome “Empresa” (com “E” maiúsculo) para o parâmetro no relatório e tentarmos passar o valor utilizando o nome “empresa” (com “e” minúsculo), o Report Viewer acusará um erro (sempre clique em “View Detail” para ter uma informação mais detalhada dos erros do Report Viewer):

Parâmetros como filtro do relatório

Um outro exemplo clássico da utilização de parâmetros em relatórios é a filtragem de dados. Imagine um relatório que traz uma lista de Produtos com as suas categorias. Não seria interessante possibilitar a filtragem desse relatório por categoria?

Para fazer isso, você só precisa criar o parâmetro (como vimos anteriormente) que receberá o ID da categoria a ser utilizada no filtro. Em seguida, nós abrimos a janela de propriedades do Tablix:

E definimos um novo filtro na aba “Filter“:

Em “Expression” nós definimos a seguinte sentença:

=IIf(Not IsNothing(Parameters!CategoriaID.Value), Fields!CategoriaID.Value = Parameters!CategoriaID.Value, True)

E em “Value“, nós definimos o valor “True“:

=True

Isso fará com que o Tablix seja filtrado quando algum valor for passado para o parâmetro “CategoriaID“. Caso contrário (se nenhum valor for passado para esse parâmetro), nenhum filtro será aplicado (ou seja, todos os registros serão exibidos).

O código para mandar um valor selecionado em um ComboBox de categorias seria este:

            // C#
            this.reportViewer1.LocalReport.SetParameters(new Microsoft.Reporting.WinForms.ReportParameter("CategoriaID", comboBoxCategoria.SelectedValue.ToString()));
            this.reportViewer1.RefreshReport();
        ' VB.NET
        Me.ReportViewer1.LocalReport.SetParameters(New Microsoft.Reporting.WinForms.ReportParameter("CategoriaID", ComboBoxCategoria.SelectedValue.ToString()))
        Me.ReportViewer1.RefreshReport()

Já o código para mandar um valor em branco para esse parâmetro (de forma que todos os Produtos sejam exibidos, sem filtro) seria este:

            // C#
            this.reportViewer1.LocalReport.SetParameters(new Microsoft.Reporting.WinForms.ReportParameter("CategoriaID", (string)null));
            this.reportViewer1.RefreshReport();
        ' VB.NET
        Me.ReportViewer1.LocalReport.SetParameters(New Microsoft.Reporting.WinForms.ReportParameter("CategoriaID", DirectCast(Nothing, String)))
        Me.ReportViewer1.RefreshReport()

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.

Concluindo

A funcionalidade de parâmetros é essencial ao desenvolvermos os relatórios das nossas aplicações. Com ela, nós conseguimos enviar valores estáticos para os relatórios, que poderão ser utilizados para exibir alguma informação, ou até mesmo para filtrarmos os dados do relatório.

No vídeo de hoje você conferiu como utilizar parâmetros no Report Viewer, tanto como valor estático (que você pode utilizar em um TextBox ou para fazer o carregamento de uma imagem dinamicamente) quanto para filtragem do relatório.

E você, já precisou passar valores estáticos para relatórios do Report Viewer? Utilizou a funcionalidade de parâmetros? Encontrou alguma dificuldade ou tudo funcionou conforme o esperado? Conte-nos mais detalhes na caixa de comentários logo abaixo!

Até a próxima!

André Lima

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/

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Trabalhando com parâmetros no Report Viewer appeared first on André Alves de Lima.

Configurando o idioma do Report Viewer

$
0
0

Quando instalamos aplicações desktop em computadores com sistema operacional que não esteja traduzido para português, temos que nos atentar para a globalização das nossas aplicações. Em alguns casos, os controles podem vir formatados em inglês (ou no formato do idioma que estiver configurado no computador). Se a aplicação conta com relatórios do Report Viewer, esse é um ponto que devemos prestar bastante atenção, uma vez que, por padrão, os relatórios trazem o formato de datas e números em inglês. Como fazemos para alterar o idioma do Report Viewer? É isso que eu mostro para você no vídeo de hoje:

Alterando o idioma do controle

A alteração do idioma do Report Viewer pode ser dividida em duas partes. Primeiro, temos a tradução do controle em si (labels, tooltips, mensagens de erro, etc). E, depois, temos a configuração do idioma do relatório (para que as datas, números e moedas venham no formato correto).

Para alterarmos o idioma do controle do Report Viewer, temos que configurar o idioma da aplicação como um todo. Fazemos isso setando a cultura da thread principal da aplicação. Isso pode ser feito no método “main” ou no construtor do formulário principal da sua aplicação:

            // C#
            var cultura = new System.Globalization.CultureInfo("pt-BR");
            System.Threading.Thread.CurrentThread.CurrentCulture = cultura;
            System.Threading.Thread.CurrentThread.CurrentUICulture = cultura;
        ' VB.NET
        Dim Cultura = New System.Globalization.CultureInfo("pt-BR")
        System.Threading.Thread.CurrentThread.CurrentCulture = Cultura
        System.Threading.Thread.CurrentThread.CurrentUICulture = Cultura

E com isso o controle do Report Viewer exibirá mensagens, tooltips, etc. no idioma configurado:

Alterando o idioma do relatório

Dentro do relatório, nós provavelmente teremos TextBoxes com formatação de data/hora, número e moeda. Se nós não configurarmos um idioma específico dentro do relatório, muito provavelmente o Report Viewer utilizará as informações de cultura do idioma inglês americano. Ou seja, as datas aparecerão invertidas e os números com ponto como separador (ao invés de vírgula).

Para que esses tipos de controles venham com a formatação correta, nós temos que alterar a propriedade “Language” do relatório:

Ao fazermos isso, as datas e números aparecerão no formato correto. Porém, se tivermos formatado um TextBox com formato monetário, ele ficará “travado” para o formato configurado no computador de desenvolvimento (no meu caso, em Euros):

Formatando moedas

Se quisermos que as moedas também venham formatadas respeitando o idioma selecionado no relatório, nós teremos que configurar uma expressão para fazer a formatação manual (ao invés de fazermos a formatação como indicado acima). A expressão para esses tipos de TextBox seria a seguinte:

=String.Format("{0:c}", Fields!NomeDoCampo.Value)

Aí sim os campos com moedas serão formatados da maneira correta:

Sincronizando o idioma do relatório com o idioma da aplicação

Para não termos que configurar o idioma em dois lugares diferentes (na aplicação e depois em cada um dos relatórios), nós podemos configurar o idioma dos relatórios de maneira dinâmica, de forma que ele respeite automaticamente o idioma configurado na aplicação.

Se você procurar por esse assunto na internet, você encontrará muita gente sugerindo as mais diversas gambiarras para solucionar essa questão (como passar o idioma para o relatório via parâmetro, por exemplo). Porém, isso é algo muito fácil de ser resolvido. Basta configurarmos o idioma do relatório com uma expressão que retornará o idioma da aplicação. Essa informação está disponível dentro de “Built-in fields” na janela de expressões:

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.

Concluindo

No vídeo de hoje você conferiu o esquema de tradução de relatórios do Report Viewer. Primeiramente, conferimos como podemos configurar o idioma do controle do Report Viewer. Em seguida, nós aprendemos a configurar os formatos de hora, número e moeda dos nossos relatórios. Por fim, nós vimos como sincronizar o idioma da aplicação e dos relatórios.

E você, já teve problemas com os idiomas e formatações no Report Viewer? Conseguiu resolver esses problemas seguindo os passos que eu indiquei no vídeo? Ficamos aguardando as suas experiências na caixa de comentários logo abaixo.

Até a próxima!

André Lima

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Configurando o idioma do Report Viewer appeared first on André Alves de Lima.

Imprimindo direto na impressora com o Report Viewer

$
0
0

Em algumas situações, faz mais sentido imprimirmos informações direto na impressora, ao invés de exibirmos uma janela de pré-visualização para o usuário. Esse tipo de otimização é muito importante quando o usuário precisa de muita rapidez na operação. Uns tempos atrás eu mostrei como imprimir informações direto na impressora através da classe PrintDocument. Em uma outra oportunidade, eu mostrei como exportar relatórios do Report Viewer. Mas, até hoje eu ainda não mostrei como imprimir relatórios direto na impressora com o Report Viewer. É justamente isso que eu vou mostrar para você neste vídeo:

Referências

O conteúdo desse vídeo / artigo foi baseado no código apresentado pelo Brian Hartman no blog dele em 2009. Além disso, eu tomei também como base essa entrada na documentação do MSDN, que mostra um passo a passo simplificado para atingirmos esse objetivo. Misturando esses dois códigos, eu criei uma terceira versão mais simplificada, que funcionou perfeitamente nos testes que eu fiz e espero que funcione também com relatórios da sua aplicação.

Para imprimirmos relatórios direto na impressora com o Report Viewer, nós temos que dividir a operação em dois passos: primeiro exportamos os relatórios em memória (no formato “imagem“), depois imprimimos cada uma das imagens em uma página separada (utilizando a classe PrintDocument).

Dito isso, o “esqueleto” do nosso código de impressão direta ficaria assim:

        // C#
        private DataSetRelatorio CriarDataSet()
        {
            var ds = new DataSetRelatorio();

            for (int c = 1; c <= 200; c++)
            {
                ds.Item.AddItemRow(c, string.Format("Item {0}", c));
            }

            return ds;
        }

        private void btImprimir_Click(object sender, EventArgs e)
        {
            using (var ds = CriarDataSet())
            using (var relatorio = new Microsoft.Reporting.WinForms.LocalReport())
            {
                relatorio.ReportPath = "Relatorio.rdlc";
                relatorio.DataSources.Add(new Microsoft.Reporting.WinForms.ReportDataSource("DataSetRelatorio", (DataTable)ds.Item));

                Exportar(relatorio);
                Imprimir(relatorio);
            }
        }
    ' VB.NET
    Private Function CriarDataSet() As DataSetRelatorio
        Dim Ds = New DataSetRelatorio()

        For C As Integer = 1 To 200
            Ds.Item.AddItemRow(C, String.Format("Item {0}", C))
        Next

        Return Ds
    End Function

    Private Sub btImprimir_Click(sender As Object, e As EventArgs) Handles btImprimir.Click
        Using ds = CriarDataSet()
            Using Relatorio = New Microsoft.Reporting.WinForms.LocalReport()
                Relatorio.ReportPath = "Relatorio.rdlc"
                Relatorio.DataSources.Add(New Microsoft.Reporting.WinForms.ReportDataSource("DataSetRelatorio", DirectCast(ds.Item, DataTable)))

                Exportar(Relatorio)
                Imprimir(Relatorio)
            End Using
        End Using
    End Sub

Note que temos um método que retorna um DataSet para o nosso relatório. Nesse exemplo, esse método está simplesmente gerando algumas linhas em uma DataTable, que será enviada para o relatório. Obviamente, você deverá substituir esse método com o carregamento correto dos dados para o seu relatório, dependendo de como você estiver trabalhando com os dados na sua aplicação.

Exportando as páginas em memória

Como mencionei anteriormente, o primeiro passo na impressão direta do Report Viewer é a exportação das páginas em memória. A ideia nessa etapa é gerarmos uma MemoryStream para cada página do nosso relatório, sendo que cada uma dessas Streams armazenará a imagem de uma página que deverá ser impressa.

Para implementarmos essa funcionalidade, utilizaremos o método “Render” do nosso relatório. Esse é o método que utilizamos para exportarmos o relatório nos mais diversos formatos suportados, como demonstrei neste outro artigo.

Uma das sobrecargas do método “Render” recebe um call-back de geração de Streams (CreateStreamCallback). Com essa sobrecarga, nós teremos as imagens armazenadas em Streams. Para ficar mais fácil de explicar, vamos ver como é que fica o código:

        // C#
        private void Exportar(Microsoft.Reporting.WinForms.LocalReport relatorio)
        {
            Microsoft.Reporting.WinForms.Warning[] warnings;
            LimparStreams();
            relatorio.Render("image", CriarDeviceInfo(relatorio), CreateStreamCallback, out warnings);
        }

        private List<System.IO.Stream> _streams = new List<System.IO.Stream>();
        public System.IO.Stream CreateStreamCallback(string name, string extension, Encoding encoding, string mimeType, bool willSeek)
        {
            var stream = new System.IO.MemoryStream();
            _streams.Add(stream);
            return stream;
        }

        private void LimparStreams()
        {
            foreach (var stream in _streams)
            {
                stream.Dispose();
            }
            _streams.Clear();
        }
    ' VB.NET
    Private Sub Exportar(Relatorio As Microsoft.Reporting.WinForms.LocalReport)
        Dim Warnings As Microsoft.Reporting.WinForms.Warning()
        LimparStreams()
        Relatorio.Render("image", CriarDeviceInfo(Relatorio), AddressOf CreateStreamCallback, Warnings)
    End Sub

    Private Streams As New List(Of System.IO.Stream)()
    Public Function CreateStreamCallback(Name As String, Extension As String, Encoding As System.Text.Encoding, MimeType As String, WillSeek As Boolean) As System.IO.Stream
        Dim Stream = New System.IO.MemoryStream()
        Streams.Add(Stream)
        Return Stream
    End Function

    Private Sub LimparStreams()
        For Each Stream In Streams
            Stream.Dispose()
        Next
        Streams.Clear()
    End Sub

Note que essa sobrecarga do método “Render” recebe o formato que queremos utilizar (nesse caso, “image“), uma string com um “device info” (que eu explicarei logo mais), um CreateStreamCallback e um array de Warnings (não utilizado no nosso exemplo). A ideia é que, para cada página do relatório, o Report Viewer chamará o método de call-back, que deverá retornar uma Stream onde a página atual deverá ser armazenada. No nosso caso, nós criamos e retornamos uma MemoryStream, mantendo a referência na nossa lista interna.

Um detalhe importante é que, para cada chamada do método “Imprimir“, nós temos que limpar a nossa lista de Streams (com o método “LimparStreams“), senão a lista interna acumulará as Streams que tiverem sido geradas em chamadas anteriores desse método.

Gerando o DeviceInfo

Como você pode perceber, um dos parâmetros do método “Render” é o “DeviceInfo“. E o que seria isso? O parâmetro “DeviceInfo” é um XML contendo as informações dos tamanhos de página e margens que devem ser consideradas na exportação. Veja um exemplo desse XML na documentação do MSDN:

Não sei se você sabe, mas os arquivos rdlc nada mais são que arquivos XML com a definição do relatório. Dentro do XML do arquivo rdlc, nós encontramos as informações de página e margem, veja só:

Isso quer dizer que nós podemos ler as propriedades de tamanho de página e margem do nosso relatório (utilizando o método “GetDefaultPageSettings“) para gerarmos o XML do “DeviceInfo” dinamicamente. O código para fazer essa geração dinâmica ficaria assim:

        // C#
        private string CriarDeviceInfo(Microsoft.Reporting.WinForms.LocalReport relatorio)
        {
            var pageSettings = relatorio.GetDefaultPageSettings();
            return string.Format(
                System.Globalization.CultureInfo.InvariantCulture,
                @"<DeviceInfo>
                    <OutputFormat>EMF</OutputFormat>
                    <PageWidth>{0}in</PageWidth>
                    <PageHeight>{1}in</PageHeight>
                    <MarginTop>{2}in</MarginTop>
                    <MarginLeft>{3}in</MarginLeft>
                    <MarginRight>{4}in</MarginRight>
                    <MarginBottom>{5}in</MarginBottom>
                </DeviceInfo>",
                pageSettings.PaperSize.Width / 100m, pageSettings.PaperSize.Height / 100m, pageSettings.Margins.Top / 100m, pageSettings.Margins.Left / 100m, pageSettings.Margins.Right / 100m, pageSettings.Margins.Bottom / 100m);
        }
    ' VB.NET
    Private Function CriarDeviceInfo(Relatorio As Microsoft.Reporting.WinForms.LocalReport) As String
        Dim PageSettings = Relatorio.GetDefaultPageSettings()
        Return String.Format(
            System.Globalization.CultureInfo.InvariantCulture,
            "<DeviceInfo><OutputFormat>EMF</OutputFormat><PageWidth>{0}in</PageWidth><PageHeight>{1}in</PageHeight><MarginTop>{2}in</MarginTop><MarginLeft>{3}in</MarginLeft><MarginRight>{4}in</MarginRight><MarginBottom>{5}in</MarginBottom></DeviceInfo>",
            PageSettings.PaperSize.Width / 100D, PageSettings.PaperSize.Height / 100D, PageSettings.Margins.Top / 100D, PageSettings.Margins.Left / 100D,
            PageSettings.Margins.Right / 100D, PageSettings.Margins.Bottom / 100D)
    End Function

Imprimindo as imagens geradas em memória

Uma vez geradas as Streams contendo as páginas do nosso relatório em memória, chegou a hora de efetivamente imprimirmos essas Streams. Para isso, nós utilizaremos um PrintDocument, que é uma classe disponível no namespace System.Drawing.Printing que implementa a possibilidade de imprimirmos informações direto na impressora (nesse caso, as imagens representando as páginas do nosso relatório).

O código para fazermos a impressão não é muito complicado. Primeiramente, temos que configurar mais uma vez as informações de página e margens do PrintDocument, copiando essas informações do relatório. Em seguida, nós configuramos o evento “PrintPage” do nosso PrintDocument e chamamos o método “Print” para iniciarmos a impressão.

Dentro da implementação do evento “PrintPage“, nós temos que imprimir a informação de cada uma das páginas do nosso relatório. Esse método será chamado para cada página que deverá ser impressa, por isso, temos que utilizar uma variável de controle para sabermos qual página estamos imprimindo no ciclo atual.

Para imprimirmos a Stream que foi gerada anteriormente, nós utilizamos um objeto do tipo “Metafile“, que é o tipo mais genérico de imagem. Como o construtor dessa classe recebe uma Stream, nós simplesmente passamos a Stream que foi exportada anteriormente e tudo deve funcionar perfeitamente. Nós só não podemos esquecer de rebobinar a Stream (utilizando o método “Seek“), senão a impressão sairá em branco!

Por fim, a última operação dentro do evento “PrintPage” será a configuração da propriedade “HasMorePages“. É através dessa propriedade que o PrintDocument saberá se o evento “PrintPage” deverá ser chamado mais uma vez (para imprimir a próxima página) ou não.

O código final para fazermos a impressão das Streams é o seguinte:

        // C#
        private void Imprimir(Microsoft.Reporting.WinForms.LocalReport relatorio)
        {
            using (var pd = new System.Drawing.Printing.PrintDocument())
            {
                pd.PrinterSettings.PrinterName = "PrimoPDF";
                var pageSettings = new System.Drawing.Printing.PageSettings();
                var pageSettingsRelatorio = relatorio.GetDefaultPageSettings();
                pageSettings.PaperSize = pageSettingsRelatorio.PaperSize;
                pageSettings.Margins = pageSettingsRelatorio.Margins;
                pd.DefaultPageSettings = pageSettings;

                pd.PrintPage += Pd_PrintPage;
                _streamAtual = 0;
                pd.Print();
            }
        }

        private int _streamAtual;
        private void Pd_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
        {
            var stream = _streams[_streamAtual];
            stream.Seek(0, System.IO.SeekOrigin.Begin);

            using (var metadata = new System.Drawing.Imaging.Metafile(stream))
            {
                e.Graphics.DrawImage(metadata, e.PageBounds);
            }

            _streamAtual++;
            e.HasMorePages = _streamAtual < _streams.Count;
        }
    ' VB.NET
    Private Sub Imprimir(Relatorio As Microsoft.Reporting.WinForms.LocalReport)
        Using Pd = New System.Drawing.Printing.PrintDocument()
            Pd.PrinterSettings.PrinterName = "PrimoPDF"
            Dim PageSettings = New System.Drawing.Printing.PageSettings()
            Dim PageSettingsRelatorio = Relatorio.GetDefaultPageSettings()
            PageSettings.PaperSize = PageSettingsRelatorio.PaperSize
            PageSettings.Margins = PageSettingsRelatorio.Margins
            Pd.DefaultPageSettings = PageSettings

            AddHandler Pd.PrintPage, AddressOf Pd_PrintPage
            StreamAtual = 0
            Pd.Print()
        End Using
    End Sub

    Private StreamAtual As Integer
    Private Sub Pd_PrintPage(sender As Object, e As System.Drawing.Printing.PrintPageEventArgs)
        Dim Stream = Streams(StreamAtual)
        Stream.Seek(0, System.IO.SeekOrigin.Begin)

        Using metadata = New System.Drawing.Imaging.Metafile(Stream)
            e.Graphics.DrawImage(metadata, e.PageBounds)
        End Using

        StreamAtual += 1
        e.HasMorePages = StreamAtual < Streams.Count
    End Sub

Utilizando a classe ReportPrintDocument

Se você achou todo esse código muito complicado, não se preocupe. Como eu mencionei no início do artigo, o Brian Hartman implementou uma classe que encapsula toda essa parafernalha que eu mostrei até agora. Para utilizá-la, basta baixar o arquivo correspondente a adicioná-lo no seu projeto. Você pode baixar a versão em C# aqui ou a versão em VB.NET aqui, e depois você pode adicionar no seu projeto utilizando a opção “Add -> Existing Item“:

Uma vez que você tiver adicionado essa classe no projeto, a utilização é muito simples. Basta criarmos uma instância da classe “ReportPrintDocument” (que fica no namespace “PrintReportSample“) passando o relatório e, em seguida, chamamos o método “Print“:

        // C#
        private void btImprimir_Click(object sender, EventArgs e)
        {
            using (var ds = CriarDataSet())
            using (var relatorio = new Microsoft.Reporting.WinForms.LocalReport())
            {
                relatorio.ReportPath = "Relatorio.rdlc";
                relatorio.DataSources.Add(new Microsoft.Reporting.WinForms.ReportDataSource("DataSetRelatorio", (DataTable)ds.Item));

                using (var rpd = new PrintReportSample.ReportPrintDocument(relatorio))
                {
                    rpd.Print();
                }
            }
        }
    ' VB.NET
    Private Sub btImprimir_Click(sender As Object, e As EventArgs) Handles btImprimir.Click
        Using ds = CriarDataSet()
            Using Relatorio = New Microsoft.Reporting.WinForms.LocalReport()
                Relatorio.ReportPath = "Relatorio.rdlc"
                Relatorio.DataSources.Add(New Microsoft.Reporting.WinForms.ReportDataSource("DataSetRelatorio", DirectCast(ds.Item, DataTable)))

                Using Rpd = New PrintReportSample.ReportPrintDocument(Relatorio)
                    Rpd.Print()
                End Using
            End Using
        End Using
    End Sub

Bem mais simples, não é mesmo? Porém, é muito importante sabermos o que está por trás de todo o código implementado nessa classe. Dessa forma, caso algo não funcione 100% corretamente para algum relatório específico, fica mais fácil de procurarmos a origem do erro. Foi justamente por isso que eu decidi mostrar primeiramente um passo a passo de como podemos fazer essa impressão de forma manual, sem utilizar essa classe utilitária do Brian Hartman.

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.

Concluindo

O processo de impressão direta de relatórios do Report Viewer não é nem tão simples, nem tão complicado. Como nós não temos um método que implementa esse tipo de impressão nativamente, nós precisamos primeiramente exportar as páginas do nosso relatório em memória e, em seguida, imprimimos cada página utilizando um PrintDocument.

Como você pode observar, se você não estiver a fim de aprender o que está por trás de toda essa implementação, não tem problema. Basta baixar e utilizar a classe “ReportPrintDocument” implementada pelo Brian Hartman, que eu disponibilizei tanto em C# (original do Brian Hartman) e VB.NET (que eu converti por conta própria).

E você, já precisou imprimir relatórios do Report Viewer direto na impressora? Você já tinha conhecimento dessa classe do Brian Hartman ou você fez a implementação “na mão” utilizando o tutorial do MSDN? No final das contas deu tudo certo ou teve algum relatório em que a impressão direta não funcionou? Fico aguardando os seus comentários logo abaixo!

Até a próxima!

André Lima

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Imprimindo direto na impressora com o Report Viewer appeared first on André Alves de Lima.

Definindo a estrutura de campos do Report Viewer sem DataSet ou classe

$
0
0

DataSets são elementos importantíssimos no desenvolvimento de relatórios, independente da ferramenta que você estiver utilizando. Afinal de contas, são eles que definem a estrutura de campos que os relatórios poderão exibir. Com o Report Viewer não poderia ser diferente – ele também utiliza o conceito de DataSets na definição dos relatórios.

Um grande desafio que temos quando a nossa aplicação vai crescendo é: como conseguimos manter a imensa quantidade de DataSets ou classes de dados no nosso projeto sem que tudo acabe ficando uma verdadeira bagunça? Não seria muito legal se pudéssemos criar a estrutura de campos do Report Viewer sem DataSet ou classe? No Crystal Reports temos os arquivos TTX para nos ajudar com essa tarefa, mas e quanto ao Report Viewer? Ele tem algo parecido?

Por padrão, no Report Viewer nós só conseguimos definir a estrutura de campos dos relatórios com DataSets tipados ou classes de dados. Para resolver essa limitação, eu estive trabalhando algumas horas em uma pequena ferramenta que vai nos ajudar a editar a definição de campos dos relatórios do Report Viewer sem que nós precisemos criar DataSets tipados ou classes de dados no nosso projeto.

No artigo de hoje eu vou mostrar para você como é que essa ferramenta funciona. Gostou da ideia? Então vamos lá!

Como são definidos os DataSets do Report Viewer?

Antes de prosseguirmos, é importante entendermos a maneira como o Report Viewer salva a definição dos DataSets no arquivo RDLC. Não sei se você sabe, mas os arquivos RDLC são basicamente XMLs com uma estrutura pré-estabelecida. Ao abrirmos um arquivo RDLC em um editor de texto, teremos uma ideia de como esses arquivos são estruturados:

Como já era de se imaginar, as estruturas dos DataSets do relatório também estão definidas nesse XML, mais especificamente dentro das tags “DataSources” e “DataSets“. Veja só um exemplo dessa definição:

Independentemente da maneira que nós utilizemos para adicionar um DataSet no Report Viewer (seja através de DataSets tipados, classes de dados ou serviços), o arquivo RDLC conterá essas duas tags onde a estrutura de campos será definida.

Com isso em mente, se nós quisermos adicionar, remover ou alterar campos de um DataSet do nosso relatório (ou até mesmo criar um novo DataSet), nós só temos que alterar o conteúdo dessas tags.

Apresentando o Report Viewer DataSet Editor

Se eu chegasse aqui e falasse que nós teremos que editar essas tags manualmente no arquivo RDLC, você provavelmente riria da minha cara. As chances são grandes de quebrarmos alguma coisa na estrutura do arquivo se nós começarmos a editar o seu conteúdo manualmente.

Pensando nisso, eu investi algumas horas na criação de uma ferramenta que faz a leitura do arquivo RDLC, mostra a estrutura dos DataSets do relatório em um grid e permite adicionar, alterar ou remover campos, bem como criar novos DataSets para o relatório:

Essa ferramenta, a qual eu dei o singelo nome de “Report Viewer DataSet Editor“, é open source e o código está disponível no GitHub. Como você pode notar, o projeto está bem no começo. Ainda não adicionei descrição do projeto, comentários, etc. E não repare no código! Ele está bem rudimentar, sem testes de unidade e com uma estrutura bem simples por enquanto.

Eu testei a ferramenta com alguns relatórios de exemplo e ela funcionou muito bem. Mas, ainda tem muito para testar e evoluir. Caso você queira contribuir, é só mandar um pull request lá no GitHub.

Para utilizar essa ferramenta, baixe a última release neste link. Como o executável não está assinado, se você tentar rodar a aplicação em um computador com Windows 10, o SmartScreen vai falar que a aplicação não é confiável. Obviamente, essa aplicação é confiável (você pode ver o código fonte no próprio GitHub), portanto ignore essas mensagens do SmartScreen:

Se por algum motivo você não confiar no executável, baixe o código fonte no GitHub e compile você mesmo utilizando o Visual Studio.

Criando um novo relatório

Para demonstrar o funcionamento dessa ferramenta, vamos criar um novo projeto do tipo “Windows Forms Application” e, dentro desse projeto, vamos adicionar um novo relatório, dando o nome de “Relatorio.rdlc” para o arquivo que será criado:

Nota: caso você não encontre o item “Report”, veja como adicionar o Report Viewer no Visual Studio 2015 e no Visual Studio 2017.

Com o arquivo RDLC criado, vamos abri-lo com o Report Viewer DataSet Editor para definirmos um novo DataSet e a sua estrutura de campos. Como o relatório ainda não tem nenhum DataSet definido, o ComboBox “DataSet” e o grid aparecerão em branco. A única opção nesse caso é clicarmos no botão “New DataSet” para criarmos um novo DataSet nesse relatório. Vamos dar o nome de “DataSetRelatorio” para o novo DataSet que será criado:

Em seguida, vamos adicionar as colunas desse DataSet. Para simplificarmos, vamos criar somente duas colunas do tipo “String” – uma chamada “Nome” e outra chamada “Sobrenome“:

Salve as alterações clicando no botão “Save changes“:

Pronto! A partir daí, se voltarmos no designer do nosso relatório, nós veremos que o “DataSetRelatorio” estará disponível:

Vamos montar um layout bem simples para o relatório, adicionando somente uma tabela com as duas colunas (nome e sobrenome):

Alimentando o relatório através de um DataGridView

Agora que nós temos o nosso relatório montado, vamos ver como podemos alimentá-lo sem utilizar nenhuma classe ou DataSet. Imagine que nós tenhamos uma janela com um DataGridView, contendo as colunas “Nome” e “Sobrenome“:

Como o método de carregamento de dados do Report Viewer suporta não só DataTables, mas também, coleções enumeráveis, nada impede que nós criemos um Enumerable dos dados do DataGridView para mandarmos para o relatório. Isso é muito fácil de ser implementado, utilizando LINQ.

Para não perdermos tempo montando um formulário para exibirmos os dados desse relatório, vamos utilizar o formulário que eu criei no meu artigo onde eu mostro como carregar múltiplos relatórios do Report Viewer com o mesmo formulário. Uma vez adicionado esse formulário no projeto, veja como fica fácil o código para montarmos uma coleção enumerável utilizando os dados do DataGridView:

        // C#
        private void btRelatorio_Click(object sender, EventArgs e)
        {
            var dadosRelatorio = from DataGridViewRow linha in dataGridViewNomes.Rows
                                 select new
                                 {
                                     Nome = linha.Cells["Nome"].Value,
                                     Sobrenome = linha.Cells["Sobrenome"].Value
                                 };

            FormRelatorio.ShowReport("ReportViewerSemDataSet.Relatorio.rdlc", true, new Dictionary<string, object>() { { "DataSetRelatorio", dadosRelatorio.AsEnumerable() } });
        }
    ' VB.NET
    Private Sub btRelatorio_Click(sender As Object, e As EventArgs) Handles btRelatorio.Click
        Dim DadosRelatorio = From linha In dataGridViewNomes.Rows
                             Select New With {.Nome = linha.Cells("Nome").Value, .Sobrenome = linha.Cells("Sobrenome").Value}

        FormRelatorio.ShowReport("ReportViewerSemDataSet.VB.Relatorio.rdlc", True, New Dictionary(Of String, Object)() From {{"DataSetRelatorio", DadosRelatorio.AsEnumerable()}})
    End Sub

Execute a aplicação, preencha o grid com alguns dados, chame o relatório e veja o resultado:

Ahá! Aí está um relatório do Report Viewer que foi construído e carregado sem a utilização de DataSets tipados ou classes de dados. Bacana, não é mesmo?

Concluindo

O fato de sempre termos que definir DataSets tipados ou classes de dados para desenharmos o layout dos nossos relatórios do Report Viewer pode fazer com que o nosso projeto se torne bem bagunçado. Imagine um projeto com 50 relatórios. Muito provavelmente esse projeto terá inúmeros DataSets tipados ou classes de dados que só servem para desenharmos e carregarmos os relatórios.

No artigo de hoje eu apresentei para você a ferramenta open-source que eu estou desenvolvendo, o Report Viewer DataSet Editor. Essa ferramenta permite a definição e alteração dos DataSets do relatório sem que precisemos criar DataSets tipados ou classes de dados no nosso projeto. Isso facilita bastante a nossa vida e deixa o nosso projeto mais limpo.

Atenção! Essa ferramenta ainda está bem crua! Eu testei com alguns relatórios e funcionou perfeitamente, porém, você deve utilizá-la por sua conta e risco. Lembre-se sempre de fazer um backup do seu arquivo RDLC antes de aplicar as alterações!

Antes de me despedir, convido você a inscrever-se na minha newsletter. Ao fazer isso, você receberá um e-mail toda semana sobre o artigo publicado, ficará sabendo em primeira mão sobre o artigo da próxima semana e receberá também dicas “bônus” que eu só compartilho por e-mail. Além disso, você já deve ter percebido que eu recebo muitas sugestões de temas e eu costumo dar prioridade às sugestões vindas de inscritos da minha newsletter. 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/document-agreement-documents-sign-428338/

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Definindo a estrutura de campos do Report Viewer sem DataSet ou classe appeared first on André Alves de Lima.

Imprimindo múltiplas vias no Report Viewer

$
0
0

Alguns tipos de relatórios precisam ser impressos em múltiplas vias. Deixar a impressão das vias adicionais a cargo do usuário é um tiro no pé. Muito provavelmente ele esquecerá de configurar que o relatório deve ser impresso duas vezes e, todas as vezes que ele se esquecer disso, ele xingará mentalmente a empresa (ou desenvolvedor) que implementou aquele software sem a opção de imprimir múltiplas vias automaticamente.

Infelizmente não temos uma opção nativa que podemos configurar no Report Viewer de forma que ele imprima múltiplas vias do mesmo relatório. Porém, esse problema pode ser resolvido com algumas alterações na aplicação. No vídeo de hoje eu mostro para você três opções que podemos utilizar nos nossos projetos para imprimirmos múltiplas vias no Report Viewer:

Opção 1: Adicionando uma coluna “Via” no DataSet

Se você realmente tiver que exibir as duas vias no controle visualizador do Report Viewer (antes de realizar a impressão), ou se a primeira via for sutilmente diferente da segunda, aí não temos outra opção. Teremos que criar uma nova coluna no DataSet para representar o número da via:

Em seguida, nós temos que duplicar os dados da tabela que está alimentando o relatório (ou triplicar, quadruplicar, etc. – depende da quantidade de vias necessárias). No vídeo eu mostro um método que eu implementei para fazer a duplicação dos dados. Esse método recebe a DataTable original e retorna uma DataTable com “N” cópias das linhas:

        // C#
        private DataTable GerenciarVias(DataTable origem, string nomeColunaVia, int qtdVias)
        {
            var retorno = origem.Copy();

            for (var c = 2; c <= qtdVias; c++)
            {
                foreach (DataRow linha in origem.Rows)
                {
                    var novaLinha = retorno.NewRow();
                    novaLinha.ItemArray = (object[])linha.ItemArray.Clone();
                    novaLinha[nomeColunaVia] = c;
                    retorno.Rows.Add(novaLinha);
                }
            }

            return retorno;
        }
    ' VB.NET
    Private Function GerenciarVias(Origem As DataTable, NomeColunaVia As String, QtdVias As Integer) As DataTable
        Dim Retorno = Origem.Copy()

        For C = 2 To QtdVias
            For Each Linha As DataRow In Origem.Rows
                Dim NovaLinha = Retorno.NewRow()
                NovaLinha.ItemArray = DirectCast(Linha.ItemArray.Clone(), Object())
                NovaLinha(NomeColunaVia) = C
                Retorno.Rows.Add(NovaLinha)
            Next
        Next

        Return Retorno
    End Function

Com esse método à nossa disposição (você pode colocá-lo em uma classe estática ou biblioteca de forma que ele possa ser utilizado em múltiplos lugares), basta chamarmos passando a DataTable original e a quantidade de vias desejada. Por fim, nós trocamos a DataSource do relatório, de forma que ele utilize essa nova DataTable com os dados duplicados:

            // C#
            var novaTabela = GerenciarVias(this.DataSetRelatorio.Produto, "Via", 2);
            this.reportViewer1.LocalReport.DataSources.Clear();
            this.reportViewer1.LocalReport.DataSources.Add(new Microsoft.Reporting.WinForms.ReportDataSource("DataSetRelatorio", novaTabela));
            this.reportViewer1.RefreshReport();
        ' VB.NET
        Dim NovaTabela = GerenciarVias(Me.DataSetRelatorio.Produto, "Via", 2)
        Me.ReportViewer1.LocalReport.DataSources.Clear()
        Me.ReportViewer1.LocalReport.DataSources.Add(New Microsoft.Reporting.WinForms.ReportDataSource("DataSetRelatorio", NovaTabela))
        Me.ReportViewer1.RefreshReport()

Uma vez alterado o código da nossa aplicação, nós temos que ajustar também o nosso relatório. A primeira coisa que vamos fazer é dar um “refresh” nos campos do relatório, a fim de que o novo campo “Via” seja reconhecido:

Nota: caso você esteja tendo algum problema nessa etapa e o campo “Via” não esteja aparecendo, você pode utilizar o Report Viewer DataSet Editor para adicionar esse campo no seu relatório manualmente.

Em seguida, adicionamos um agrupamento “pai” no relatório, considerando essa nova coluna “Via” como expressão de agrupamento:

Como nós não precisaremos da informação do número da via no Tablix, nós podemos deletar a coluna que foi criada. Só tome cuidado para excluir apenas a coluna, e não o agrupamento todo!

Uma última coisa que temos que configurar é a quebra de página entre as instâncias do agrupamento. Dessa forma, cada via do relatório será impressa em uma página diferente:

Pronto! Com essas alterações o relatório será gerado “N” vezes, dependendo da quantidade de vias que configuramos na chamada do método “GerenciarVias“.

Opção 2: Configurando a quantidade de cópias no evento “Print”

Uma segunda sistemática que podemos utilizar para imprimirmos múltiplas vias no Report Viewer é alterarmos automaticamente a quantidade de vias que serão impressas quando o usuário clicar no botão “imprimir“. Essa opção pode ser utilizada quando você quiser imprimir duas (ou mais) vias idênticas do relatório sem necessariamente exibi-las no controle visualizador do Report Viewer.

Para implementarmos essa funcionalidade, temos que manipular o evento “Print” do controle do Report Viewer. Dentro desse evento, nós configuramos o número de cópias que queremos imprimir:

        // C#
        private void reportViewer1_Print(object sender, Microsoft.Reporting.WinForms.ReportPrintEventArgs e)
        {
            e.PrinterSettings.Copies = 2;
        }
    ' VB.NET
    Private Sub ReportViewer1_Print(sender As Object, e As Microsoft.Reporting.WinForms.ReportPrintEventArgs) Handles ReportViewer1.Print
        e.PrinterSettings.Copies = 2
    End Sub

Com essa alteração, quando o usuário clicar em “imprimir“, a quantidade de cópias será preenchida automaticamente:

Opção 3: Configurando a quantidade de cópias no PrintDocument

Por fim, uma última opção que podemos utilizar caso estivermos imprimindo o relatório sem o controle visualizador do Report Viewer (impressão direta) seria configurarmos o número de cópias no PrintDocument. Se utilizarmos o código apresentado no meu artigo sobre impressão direta com o Report Viewer, basta configurarmos a quantidade de cópias para o PrintDocument no método “Imprimir“.

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.

Concluindo

Como você pode observar nesse vídeo, apesar de não termos uma opção nativa para imprimirmos múltiplas vias no Report Viewer, isso pode ser facilmente implementado de três maneiras. Ou nós adicionamos um campo para controlar o número da via no DataSet e agrupamos o relatório por esse campo, ou nós configuramos automaticamente o número de cópias a serem impressas no controle do Report Viewer ou nós configuramos essa mesma opção no PrintDocument, caso estejamos imprimindo o relatório direto na impressora.

Você já teve algum cenário na sua aplicação em que você precisou gerar múltiplas vias do mesmo relatório? Como é que você implementou essa funcionalidade? Utilizando uma das três maneiras indicadas nesse artigo ou de alguma outra forma? Aguardo ansiosamente os seus comentários no final do post!

Até a próxima!

André Lima

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/

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Imprimindo múltiplas vias no Report Viewer appeared first on André Alves de Lima.

Somatório de horas no Report Viewer

$
0
0

Se você já precisou somar horas no Report Viewer, muito provavelmente você teve que fazer alguma gambiarra. Se tentarmos somar campos do tipo DateTime ou TimeStamp, o resultado não será o esperado. Dessa forma, temos que fazer esse tipo de somatório de horas no Report Viewer “na mão“.

No vídeo de hoje eu mostro para você o jeito menos “gambiarrado” de se implementar esse tipo de somatório, onde convertemos toda a informação em segundos, somamos e depois formatamos o resultado adequadamente. Veja só o resultado no vídeo de hoje:

Como armazenamos informações de horas?

Quando temos que armazenar informações relacionadas a horas, eu consigo visualizar três alternativas:

Campos DateTime: considerando somente a parte das horas, minutos e segundos, ignorando o conteúdo da data em si
Campos TimeSpan: na minha opinião é a melhor estrutura para armazenar um intervalo de tempo, afinal, é justamente para isso que essa classe foi criada
Campos decimais: o horário é convertido em horas decimais, onde, por exemplo, o valor 2.5 corresponderia a duas horas e meia

Tendo como base essa realidade, eu preparei um relatório extremamente simples com informações de horas nesses três formatos:

A estratégia de sumarização de horas

Para fazermos o somatório de horas no Report Viewer, nós seguiremos uma estratégia muito simples. Primeiro nós converteremos as informações de horas em segundos. Depois, nós adicionaremos esse total de segundos em um DateTime com base “zero horas“. Com isso nós teremos a quantidade de horas, minutos e segundos, porém, nós perderemos a informação de dias, caso o total passe de 24 horas.

O cálculo da quantidade de dias pode ser feito dividindo a mesma somatória de segundos que utilizamos no passo anterior pela quantidade de segundos presentes em um dia (86400 segundos). Se pegarmos a parte inteira dessa divisão, teremos a quantidade de dias!

Somando horas decimais

Vamos começar com o somatório de horas decimais. Nesse caso, como temos que converter a informação para segundos, nós multiplicaremos tudo por 3600 (que é a quantidade de segundos presentes em uma hora). Em seguida, nós adicionamos esse total de segundos em um DateTime “zero hora” através da função “DateAdd“. Por fim, nós calculamos a quantidade de dias dividindo a somatória de segundos por 86400 e considerando somente a parte inteira através da função “Floor“.

Veja só como é que fica a expressão:

=Floor(Sum(Fields!HorasDecimal.Value) * 3600 / 86400) & ":" & Format(DateAdd("s", Sum(Fields!HorasDecimal.Value * 3600), "00:00:00"), "HH:mm:ss")

Somando TimeStamps

Para somarmos horas que estejam armazenadas em TimeStamps, o processo é um pouco mais simples, uma vez que nós temos a propriedade “TotalSeconds” que já retorna a quantidade total de segundos do TimeStamp. Apesar dessa propriedade não aparecer no IntelliSense, ela está disponível em tempo de execução e conseguimos utilizá-la sem problema algum. Nesse caso, a expressão fica assim:

=Floor(Sum(Fields!HorasTimeSpan.Value.TotalSeconds) / 86400) & ":" & Format(DateAdd("s", Sum(Fields!HorasTimeSpan.Value.TotalSeconds), "00:00:00"), "HH:mm:ss")

Somando DateTimes

O somatório de informações do tipo DateTime é muito parecido com o somatório de TimeStamps, uma vez que a classe DateTime possui a propriedade “TimeOfDay” que é justamente um TimeStamp representando a parte das horas, minutos e segundos do DateTime:

=Floor(Sum(Fields!HorasDateTime.Value.TimeOfDay.TotalSeconds) / 86400) & ":" & Format(DateAdd("s", Sum(Fields!HorasDateTime.Value.TimeOfDay.TotalSeconds), "00:00:00"), "HH:mm:ss")

E com isso temos o somatório de horas no Report Viewer tanto com DateTime quanto TimeStamp e valores decimais:

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.

Concluindo

Apesar do Report Viewer não ter suporte nativo ao somatório de horas, você viu neste vídeo que esse tipo de sumarização é totalmente implementável utilizando algumas conversões e cálculos. Se convertermos todas as informações para segundos e depois adicionarmos o total em um DateTime “zero hora“, nós teremos o resultado esperado, independentemente da estrutura de dados que você estiver utilizando para armazenar as horas, seja DateTime, TimeStamp ou valores decimais.

E você, já precisou somar horas no Report Viewer? Como é que você acabou saindo dessa situação? Você utilizou exatamente essas fórmulas ou acabou fazendo de alguma outra maneira diferente? Conte-nos mais detalhes na caixa de comentários logo abaixo!

Até a próxima!

André Lima

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Somatório de horas no Report Viewer appeared first on André Alves de Lima.


Trabalhando com código de barras no Report Viewer

$
0
0

Um dos assuntos mais requisitados com relação ao Report Viewer é a questão da utilização de código de barras nos relatórios. Como é que podemos exibir código de barras no Report Viewer?

Pois bem, no vídeo de hoje eu vou mostrar para você as duas opções que nós temos para exibirmos código de barras nos nossos relatórios do Report Viewer. A primeira opção será através de uma fonte de código de barras. Já a segunda opção será a geração da imagem do código de barras e envio dessa imagem pronta para o relatório. Assiste aí e depois me conta o que você achou:

Opção 1: Utilizando fonte de código de barras

Uma opção que podemos empregar para exibirmos código de barras nas nossas aplicações (tanto nos relatórios como nas telas) é a utilização de fontes de código de barras. Muitos tipos de códigos de barras (se você ainda não sabe, existem inúmeros tipos diferentes) possuem fontes que podem ser instaladas e convertem automaticamente texto em código de barras. Por exemplo, se pesquisarmos por “free barcode 128 font” no Google (128 é um tipo de código de barras, talvez o mais conhecido), encontraremos muitas opções que podemos utilizar:

Para testar essa sistemática, eu baixei a fonte “Code 128” do site dafont.com. Uma vez instalada, nós podemos simplesmente formatar um TextBox do relatório escolhendo essa fonte:

Veja só o resultado:

Dependendo do tipo de código de barras, você encontrará facilmente fontes gratuitas na internet. Caso você não encontre, aí você terá que partir para a segunda opção.

Opção 2: Enviando imagem do código de barras para o relatório

A segunda opção que temos para exibirmos código de barras no Report Viewer é a geração de uma imagem com o código de barras no lado da aplicação e o envio dessa imagem pronta para o relatório. Isso quer dizer que nós teremos que criar uma nova coluna do tipo “byte[]” na DataTable que está alimentando o relatório (ou uma nova propriedade, caso você esteja alimentando o relatório através de classes e não através de DataTables). Vamos dar o nome de “ImagemCB” (imagem do código de barras) para essa nova coluna:

Feito isso, temos que dar um “refresh” nos campos do DataSet do relatório para que a nova coluna apareça:

Agora nós podemos adicionar uma nova coluna na nossa tabela do relatório e, dentro dessa coluna, nós colocaremos um controle do tipo “Image“:

Nas propriedades da imagem, nós temos que configurar que o conteúdo dela virá do banco de dados (opção “Database“) e a coluna correspondente é a “ImagemCB” (que é justamente a nova coluna que criamos anteriormente):

Vamos também configurar o tamanho da imagem para que ela seja automaticamente redimensionada para caber na célula da tabela, além de adicionarmos um “padding” para que o código de barras não saia grudado nas bordas da célula:

Agora que nós já preparamos o nosso relatório para que a imagem do código de barras seja exibida, como é que nós fazemos para gerarmos a imagem para cada produto? Simples, nós utilizaremos uma biblioteca que já implementa essa funcionalidade!

A biblioteca open source mais conhecida que eu encontrei para geração de códigos de barras no .NET é a BarcodeLib. O código fonte dessa biblioteca está disponível no GitHub e você encontra os releases dela no NuGet também. Além do “Code 128“, ela suporta também outros formatos conhecidos de código de barras.

Para utilizá-la no nosso projeto, vamos adicionar uma referência através do NuGet:

A chamada para gerarmos uma imagem do código de barras com a biblioteca BarcodeLib é muito simples. Nós só temos que chamar o método “Encode” passando o tipo de código de barras e o conteúdo dele. Porém, como o relatório está esperando um array de bytes com a imagem, nós temos que converter o retorno da biblioteca (que será uma instância de “Image“). Para isso, eu utilizei o método “ImageToByteArray” que eu encontrei nesta thread do StackOverflow. Veja como é que fica o código completo:

// C#
private void Form1_Load(object sender, EventArgs e)
{
	using (var bc = new BarcodeLib.Barcode())
	{
		this.DataSetRelatorio.DataTableProduto.AddDataTableProdutoRow("Produto 1", "12345", ImageToByteArray(bc.Encode(BarcodeLib.TYPE.CODE128, "12345")));
		this.DataSetRelatorio.DataTableProduto.AddDataTableProdutoRow("Produto 2", "23456", ImageToByteArray(bc.Encode(BarcodeLib.TYPE.CODE128, "23456")));
		this.DataSetRelatorio.DataTableProduto.AddDataTableProdutoRow("Produto 3", "34567", ImageToByteArray(bc.Encode(BarcodeLib.TYPE.CODE128, "34567")));
		this.DataSetRelatorio.DataTableProduto.AddDataTableProdutoRow("Produto 4", "45678", ImageToByteArray(bc.Encode(BarcodeLib.TYPE.CODE128, "45678")));
		this.DataSetRelatorio.DataTableProduto.AddDataTableProdutoRow("Produto 5", "56789", ImageToByteArray(bc.Encode(BarcodeLib.TYPE.CODE128, "56789")));
	}

	this.reportViewer1.RefreshReport();
}

public static byte[] ImageToByteArray(System.Drawing.Image image)
{
	using(var ms = new MemoryStream())
	{
		image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
		return ms.ToArray();
	}
}
    ' VB.NET
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Using Bc = New BarcodeLib.Barcode()
            Me.DataSetRelatorio.DataTableProduto.AddDataTableProdutoRow("Produto 1", "12345", ImageToByteArray(Bc.Encode(BarcodeLib.TYPE.CODE128, "12345")))
            Me.DataSetRelatorio.DataTableProduto.AddDataTableProdutoRow("Produto 2", "23456", ImageToByteArray(Bc.Encode(BarcodeLib.TYPE.CODE128, "23456")))
            Me.DataSetRelatorio.DataTableProduto.AddDataTableProdutoRow("Produto 3", "34567", ImageToByteArray(Bc.Encode(BarcodeLib.TYPE.CODE128, "34567")))
            Me.DataSetRelatorio.DataTableProduto.AddDataTableProdutoRow("Produto 4", "45678", ImageToByteArray(Bc.Encode(BarcodeLib.TYPE.CODE128, "45678")))
            Me.DataSetRelatorio.DataTableProduto.AddDataTableProdutoRow("Produto 5", "56789", ImageToByteArray(Bc.Encode(BarcodeLib.TYPE.CODE128, "56789")))
        End Using

        Me.ReportViewer1.RefreshReport()
    End Sub

    Public Shared Function ImageToByteArray(Image As System.Drawing.Image) As Byte()
        Using Ms = New MemoryStream()
            Image.Save(Ms, Imaging.ImageFormat.Png)
            Return Ms.ToArray()
        End Using
    End Function

Execute a aplicação e confira o resultado:

Mas pera aí, por que os códigos não são iguais?

Uma coisa que você pode estar se perguntando é: se os códigos são iguais, porque o resultado é diferente com a fonte? Veja só, se dermos um zoom no relatório nós conseguiremos observar melhor a diferença:

Isso acontece porque o “Code 128” não é somente uma conversão direta de texto em código de barras. Como você pode conferir na Wikipedia, tem toda uma lógica que nós teríamos que seguir na hora de construirmos a string que deverá ser exibida com a fonte (como, por exemplo, caracteres de inicialização e finalização, além do “caractere verificador“). Se você quiser saber mais a respeito da geração da string para o “Code 128“, dê uma olhada nestes links:

Code 128/GS1-128 Barcode FAQ & Tutorial

Code 128 Check Character Calculation Examples

E se você quiser testar a geração de códigos de barras, existem inúmeros sites que fazem isso gratuitamente, como estes aqui:

Online Barcode Generator

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.

Concluindo

No artigo de hoje você conferiu duas maneiras de exibirmos código de barras no Report Viewer. A primeira delas foi através de uma fonte. Já a segunda opção foi a geração da imagem do código de barras no lado da aplicação e envio da mesma para o relatório através do DataSet.

E você, já precisou trabalhar com código de barras na sua aplicação? Como é que você resolveu essa demanda? Trabalhou com uma fonte ou alguma biblioteca para geração dos códigos? Estou curioso para saber mais sobre as suas experiências na caixa de comentários logo abaixo!

Até a próxima!

André Lima

Photo by Pixabay used under Creative Commons
https://pixabay.com/en/startup-start-up-notebooks-creative-593327/

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

Song Rocket Power Kevin MacLeod (incompetech.com)
Licensed under Creative Commons: By Attribution 3.0 License
http://creativecommons.org/licenses/by/3.0/

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Trabalhando com código de barras no Report Viewer appeared first on André Alves de Lima.

Imprimindo direto na impressora com o Crystal Reports

$
0
0

Atendendo a pedidos, hoje eu vou abordar um dos assuntos que foram escolhidos na minha última pesquisa de temas para artigos: impressão direta com o Crystal Reports! Ao contrário do que vimos algumas semanas atrás com o Report Viewer, a impressão direta no Crystal Reports é bem simples. Uma vez criada a instância de ReportDocument, nós podemos facilmente implementar essa funcionalidade através do método “PrintToPrinter“. Quer saber detalhes de como imprimir direto na impressora com o Crystal Reports? Então assiste o vídeo abaixo:

Como podemos conferir no vídeo, a primeira coisa que precisamos para imprimirmos direto na impressora com o Crystal Reports é uma instância de “ReportDocument“. Caso você não esteja trabalhando com os relatórios diretamente anexados ao seu projeto, você pode criar uma instância dessa classe e depois chamar o método “Load” para carregar o arquivo “.rpt” de onde você quiser:

            // C#
            using (var relatorio = new ReportDocument())
            {
                relatorio.Load("caminhoDoRelatorio");
            }
        ' VB.NET
        Using Relatorio = New ReportDocument()
            Relatorio.Load("CaminhoDoRelatorio")
        End Using

Por outro lado, se você estiver trabalhando com os relatórios anexados ao projeto, basta criar uma instância dele dentro de um bloco “using“. Uma vez criada a instância e configurado o DataSource do relatório, nós podemos chamar o método “PrintToPrinter“, que deverá receber as configurações da impressora e página.

Caso você já tenha uma instância de “PrinterSettings” propriamente configurada em algum lugar da sua aplicação, basta utilizá-la. Caso contrário, nós podemos exibir um diálogo onde o usuário escolherá qual impressora deverá ser utilizada (PrintDialog). Veja como é que fica o código final:

            // C#
            using (var relatorio = new RelatorioProduto())
            {
                var ds = new DataSetProduto();
                ds.Produto.AddProdutoRow("Produto 1", 1.55m);
                ds.Produto.AddProdutoRow("Produto 2", 2.35m);
                ds.Produto.AddProdutoRow("Produto 3", 3.45m);
                ds.Produto.AddProdutoRow("Produto 4", 4.75m);
                ds.Produto.AddProdutoRow("Produto 5", 5.95m);

                relatorio.SetDataSource(ds);
                using (var dialogo = new PrintDialog())
                {
                    if (dialogo.ShowDialog() == DialogResult.OK)
                    {
                        relatorio.PrintToPrinter(dialogo.PrinterSettings, dialogo.PrinterSettings.DefaultPageSettings, false);
                    }
                }
            }
        ' VB.NET
        Using Relatorio = New RelatorioProduto()
            Dim Ds = New DataSetProduto()
            Ds.Produto.AddProdutoRow("Produto 1", 1.55D)
            ds.Produto.AddProdutoRow("Produto 2", 2.35D)
            ds.Produto.AddProdutoRow("Produto 3", 3.45D)
            ds.Produto.AddProdutoRow("Produto 4", 4.75D)
            ds.Produto.AddProdutoRow("Produto 5", 5.95D)

            Relatorio.SetDataSource(ds)
            Using Dialogo = New PrintDialog()
                If Dialogo.ShowDialog() = DialogResult.OK Then
                    Relatorio.PrintToPrinter(Dialogo.PrinterSettings, Dialogo.PrinterSettings.DefaultPageSettings, False)
                End If
            End Using
        End Using

Pronto! E com esse código super-simples nós conseguimos imprimir direto na impressora com o Crystal Reports!

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.

Concluindo

No vídeo de hoje você aprendeu a imprimir relatórios direto na impressora com o Crystal Reports. Nesse caso, nós não precisamos fazer nenhuma gambiarra. Basta utilizarmos o método “PrintToPrinter” passando os parâmetros necessários e pronto! O relatório sairá impresso direto na impressora. Espero que você tenha gostado.

Até a próxima!

André Lima

Photo by Pixabay 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/

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Imprimindo direto na impressora com o Crystal Reports appeared first on André Alves de Lima.

Suporte ao Crystal Reports no Visual Studio 2017

$
0
0

Demorou, mas a SAP finalmente liberou uma versão do Crystal Reports com suporte ao Visual Studio 2017! Já faz mais ou menos um mês que o Support Pack 21 foi liberado, mas foi só agora que eu consegui testar a instalação por completo. No vídeo de hoje, veja como estão atualmente as páginas de download da versão gratuita do Crystal Reports e aprenda a adicionar o suporte ao Crystal Reports no Visual Studio 2017:

Página de download do Crystal Reports

Eu já escrevi um artigo uns tempos atrás mostrando como instalar o Crystal Reports no Visual Studio 2013. Além disso, no início do ano eu gravei também uma versão atualizada em vídeo, onde eu mostrei como ativar o Crystal Reports no Visual Studio 2015. Para fechar o ciclo, agora que a SAP liberou uma versão compatível com o Visual Studio 2017, hoje eu mostro para você como ativá-lo nessa edição.

A página de downloads do Crystal Reports para Visual Studio vem sofrendo várias mudanças ao longo dos anos. Hoje em dia, o link oficial é este. Atualmente a SAP está pedindo para que você cadastre o seu e-mail neste link para conseguir baixar o Crystal Reports. Entretanto, no próprio Wiki da SAP eles disponibilizam um outro link que cai direto nos pacotes de instalação:

Vou deixar o link aqui para que você consiga clicar e chegar na página de downloads mais facilmente:

http://www.crystalreports.com/crvs/confirm/

Qual arquivo eu devo instalar?

Quando chegamos na página de downloads, temos uma infinidade de opções de pacote de instalação:

No computador de desenvolvimento, nós temos que instalar o pacote chamado “Installation Package for Visual Studio IDE” (botão amarelo):

A instalação é bem tranquila, no estilo “next, next, finish“, portanto, não vou comentar nada sobre ela aqui. O único detalhe é que você precisa também instalar a runtime do Crystal Reports depois de ter instalado o suporte ao Visual Studio. O próprio instalador vai sugerir isso na última etapa, porém, ele só vai sugerir a instalação da runtime correspondente à arquitetura do seu computador. Se a arquitetura da sua aplicação for diferente da arquitetura do seu computador (por exemplo, seu computador é 64 bits e a sua aplicação é 32 bits), você terá que instalar a outra runtime manualmente (que é o que eu vou descrever logo abaixo).

E no computador do cliente?

No computador do cliente nós devemos instalar a famosa runtime do Crystal Reports, que são os dois primeiros itens na lista inferior da página de downloads:

Se a sua aplicação for 32 bits, instale a runtime de 32 bits. Se a aplicação for compilada em 64 bits, instale a runtime de 64 bits. Por fim, se a aplicação for compilada em “Any CPU“, instale a runtime da arquitetura correspondente do computador do cliente (se o computador for 32 bits, instale a runtime de 32 bits e se o computador for 64 bits, instale a runtime de 64 bits).

Como fica depois de instalador

Uma vez instalado o suporte ao Crystal Reports no Visual Studio 2017, você conseguirá adicionar novos relatórios no seu projeto através da opção “Add New Item“. O item do Crystal Reports estará disponível dentro da categoria “Reporting“:

Além disso, você encontrará também o controle do Crystal Reports na caixa de ferramentas, dentro da categoria “Reporting“:

Concluindo

Apesar da página de downloads do Crystal Reports ter mudado significativamente, o processo continua o mesmo das outras versões. No computador de desenvolvimento nós temos que instalar o suporte à IDE do Visual Studio e no computador do cliente nós temos que instalar a runtime. No vídeo de hoje você conferiu todo esse processo.

Antes de me despedir, 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

Photo by Pixabay 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/

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Suporte ao Crystal Reports no Visual Studio 2017 appeared first on André Alves de Lima.

Repetindo o cabeçalho do Tablix em todas as páginas no Report Viewer

$
0
0

Uma funcionalidade muito básica que normalmente necessitamos ao desenharmos os relatórios das nossas aplicações é a repetição de alguns dados em todas as páginas. Por exemplo, se tivermos uma tabela no nosso relatório, muito provavelmente nós precisaremos repetir o cabeçalho dessa tabela em todas as páginas.

O Tablix do Report Viewer tem uma configuração para repetir o cabeçalho em todas as páginas, mas essa configuração não funciona como esperamos. Na verdade, ela serve para repetir o cabeçalho dos agrupamentos em todas as páginas. Para repetirmos o cabeçalho do Tablix em todas as páginas no Report Viewer, nós temos que acessar uma configuração que fica um pouco escondida. No vídeo de hoje eu mostro para você como configurar o relatório dessa maneira:

Antes de me despedir, convido você a inscrever-se na minha newsletter. Ao fazer isso, você receberá um e-mail toda semana sobre o artigo publicado, ficará sabendo em primeira mão sobre o artigo da próxima semana e receberá também dicas “bônus” que eu só compartilho por e-mail. Além disso, você já deve ter percebido que eu recebo muitas sugestões de temas e eu costumo dar prioridade às sugestões vindas de inscritos da minha newsletter. 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/paper-messy-notes-abstract-papers-3033204/

Song Motherlode Kevin MacLeod (incompetech.com)
Licensed under Creative Commons: By Attribution 3.0 License
http://creativecommons.org/licenses/by/3.0/

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Repetindo o cabeçalho do Tablix em todas as páginas no Report Viewer appeared first on André Alves de Lima.

Cadê a tela Report Data do Report Viewer no Visual Studio?

$
0
0

Uma das principais janelas do designer do Report Viewer é a Report Data. Nela nós conseguimos definir parâmetros, configurar DataSets, entre outras coisas. Porém, se nós acidentalmente fecharmos essa janela, como é que nós podemos habilita-la novamente?

Por incrível que pareça, muita gente acaba se perdendo com essa simples atividade. O problema é que a opção “View -> Report Data” só aparece quando nós estamos focados em um relatório, e não quando estamos focados em outros tipos de arquivos (como formulários ou arquivos de código).

No vídeo de hoje, eu mostro para você exatamente o passo a passo que você tem que seguir para habilitar a tela Report Data do Report Viewer, caso você tenha fechado sem querer:

Antes de me despedir, convido você a inscrever-se na minha newsletter. Ao fazer isso, você receberá um e-mail toda semana sobre o artigo publicado, ficará sabendo em primeira mão sobre o artigo da próxima semana e receberá também 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 Jake Przespo used under Creative Commons
https://www.flickr.com/photos/jakeprzespo/4566115233/

Song Motherlode Kevin MacLeod (incompetech.com)
Licensed under Creative Commons: By Attribution 3.0 License
http://creativecommons.org/licenses/by/3.0/

Newsletter do André Lima

* indicates required



Powered by MailChimp

The post Cadê a tela Report Data do Report Viewer no Visual Studio? appeared first on André Alves de Lima.

Viewing all 61 articles
Browse latest View live