André Alves de Lima

Talking about Software Development and more…

Imprimindo direto na impressora com o Report Viewer

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

41 thoughts on “Imprimindo direto na impressora com o Report Viewer

  • Elcio Esteves disse:

    Muito interessante este post, vai me ajudar em um monte de casos. Aproveitando para te fazer uma pergunta, pois estou com um grave problema aqui. Há um tempo atrás me ajudou muito um dos seus post e até conversamos trocando informações. Aqui na empresa tínhamos vários relatórios que estavam com página A3 e quando imprimíamos em impressora, o documento era reduzido e impresso em folha A4 automático sem cortar nada, mas de um tempo para cá não tem acontecido isso os documentos só são reduzidos agora quando impressos em PDF e depois enviados a impressora. Sabe o que pode ter sido alterado para isso não acontecer mais?

    • andrealveslima disse:

      Olá Elcio!

      Infelizmente, não faço ideia.. Não teve nenhuma alteração de hardware? A impressora é a mesma, os drivers são os mesmos? Se vocês não alteraram nada na aplicação, acredito que só possa ser algo no ambiente mesmo..

      Abraço!
      André Lima

  • Airton Barros disse:

    André,
    Sempre um bom trabalho.

  • Diego disse:

    Olá Andre muto bom o vídeo e de muita utilidade, gostaria de baixar o projeto como devo proceder? Ja tenho assinatura da página

    • andrealveslima disse:

      Olá Diego! Muito obrigado pelo comentário, fico feliz que você tenha gostado.. :)

      Mandei o link para baixar os projetos de exemplo no seu email.. Qualquer coisa é só entrar em contato..

      Abraço!
      André Lima

  • E o que fazer quando o erro:

    FileNotFoundException: Não foi possível localizar o arquivo ‘C:\Users\Marcos\Documents\Visual Studio 2017\Projects\Gestor\Gestor\bin\Debug\OrdemServico.rdlc’.

    aparece?
    Como eu passo, qndo o RDLC está dentro de uma pasta no projeto?

    • andrealveslima disse:

      Olá Marcos!

      Como é que ficou o seu código? Igual ao do artigo? Ali no lugar onde eu coloco “Relatorio.rdlc”, você pode passar o caminho completo do relatório também.. Se você não passar caminho nenhum, ele tentará abrir da pasta onde o executável está localizado..

      Quando você fizer o deployment da aplicação, o relatório estará no mesmo diretório da aplicação? Caso positivo, você pode simplesmente selecionar o relatório no seu projeto e, na janela de propriedades do Visual Studio, você pode escolher para copiar o arquivo rdlc automaticamente para a pasta da aplicação (opção “Copy always”)..

      Abraço!
      André Lima

  • Damião Antunes disse:

    Boa tarde Andre, gostei muito do artigo, mas não estou conseguindo baixar o exemplo do projeto para poder entender alguns pontos, como faço para pegar esse exemplo?

  • Mariana disse:

    Oi, André, tudo bem?
    Eu estou tentando fazer uma impressão via reportviewer, sem que mostre o preview do relatório. Gostaria que, ao clicar, mostrasse apenas a caixa de diálogo para escolha da impressora. Pesquisando, descobri o PrintDialog, que eu uso assim:

    rptViewer.RefreshReport();
    rptViewer.PrintDialog();

    Isso me dá o seguinte erro:
    A operação não é válida devido ao estado atual do objeto.

    Pesquisando mais, descobri que deveria colocar o PrintDialog dentro do evento RenderingComplete, o que eu já fiz e continuo com o mesmo erro.
    Sabe o que estou fazendo de errado?

    • andrealveslima disse:

      Olá Mariana!

      A aplicação seria desktop ou web? Se for desktop você poderia seguir justamente as instruções deste vídeo onde você fez esse comentário, que eu mostro como imprimir os relatórios sem precisar mostrar o preview.. Você não tentou da maneira que eu expliquei no vídeo/artigo?

      Abraço!
      André Lima

      • Mariana disse:

        Eu estava tentando manter o padrão que já temos para a impressão com preview, mas acho que não vai dar certo.
        Poderia me mandar o seu projeto de exemplo?

        • Mariana disse:

          Estou tentando implementar o seu código. Eu consigo colocar esse trecho em uma classe ou precisa ser em um form? Percebi que dá erro quando coloco em classe.

          using (var relatorio = new Microsoft.Reporting.WinForms.LocalReport())
          {
          using (var rpd = new claReportPrintDocument(relatorio))
          {
          rpd.Print();
          }
          }

          • andrealveslima disse:

            Olá novamente, Mariana!

            Qual é o erro exatamente que você está recebendo com esse código que você postou? Para baixar os projetos de exemplo, é só assinar a minha newsletter (link “Inscreva-se” ali em cima no menu) e no e-mail de confirmação você recebe o link para baixar todos os projetos..

            Abraço!
            André Lima

          • andrealveslima disse:

            Opa, vi aqui que você já é inscrita na newsletter.. Acabei de te enviar o link para baixar os projetos..

            Abraço!
            André Lima

  • STEBAN disse:

    ESTOY MUY AGRADECIDO POR TU GRAN AYUDA.
    TENGO UNA CONSULTA TU PROYECTO QUE DESCARGUE ESTA BIEN ..IMPRIME
    PERO CUANDO QUIERO ADAPTARLO A MI PROYECTO ME BOTA ESTE ERROR

    overload resolution failed because no accessible ‘new’ accepts this number of arguments

    ESTA EN LA LINEA DE CODIGO Ds.generar_comprobante.Addgenerar_comprobanteRow(C, String.Format(“Item {0}”, C)) PARA SER MAS EXACTO EN Addgenerar_comprobanteRow

    Private Function CriarDataSet() As marketDataSet
    Dim Ds = New marketDataSet()

    For C As Integer = 1 To 200
    Ds.generar_comprobante.Addgenerar_comprobanteRow(C, String.Format(“Item {0}”, C))

    Next

    Return Ds
    End Function

    SI ME PUEDES AYUDAR PORFAVOR…

    MI CODIGO REPORTVIEWER ES ESTA

    Me.generar_comprobanteTableAdapter.Fill(Me.marketDataSet.generar_comprobante, idventa:=txtidventa.Text)

    Me.ReportViewer.RefreshReport()

    • andrealveslima disse:

      Olá Steban!

      Muito provavelmente esse erro está acontecendo porque a estrutura da sua DataTable tem uma quantidade de colunas diferente do que você está passando no método “Addgenerar_comprobanteRow”.. Quantas colunas você tem na sua DataTable? Você precisa passar exatamente as informações para cada uma das colunas dela (na ordem correta, com os tipos corretos) no método “Addgenerar_comprobanteRow”..

      Abraço!
      André Lima

  • steban disse:

    Podrias apoyarme,recien estoy empezando como desarrollador en .net yo pagare tus servicios brindados.

  • STEBAN disse:

    GRACIAS POR TU GRAN AYUDA…LA VERDAD TRATE DE COMUNICARME CONTIGO QUE ME AYUDES….NO SE QUE ESTOY HACIENDO MAL..
    TE DEJO EL CODIGO
    https://mega.nz/#!KsAyXbKC!FNy-BAFfCqRqulzTCTrzd00tkjKNR-6OLaIdf_KdjK0

    • andrealveslima disse:

      Olá novamente Steban.

      Só com o código fica difícil de ajudar.. Você precisa falar o que você já tentou fazer, os erros que você está recebendo, etc.. Mas, levando em consideração o seu primeiro comentário, aquele erro que você estava tendo ao adicionar uma linha no DataSet é justamente o que eu te falei.. A sua DataTable “generar_comprobante” tem uma infinidade de campos (venta, nombre, apelidos, etc).. Na hora de utilizar o método “Addgenerar_comprobanteRow”, você tem que passar as informações para cada uma dessas colunas, conforme indicado pelo IntelliSense:

      No código que você me mandou anteriormente, você só está tentando passar o valor para algumas colunas, e isso não faz sentido.. Ao utilizar esse método você precisa passar o valor para todas as colunas..

      Abraço!
      André Lima

  • Bruno disse:

    O artigo me ajudou bastante. Porém ainda estou com um problema na renderização – a emf criado ficou maior do que o layout do relatório. Com isso , o que era pra ser impresso em uma página, está sendo impresso em 2, com as fontes distorcidas. Ainda não consegui achar o problema, pois pelo debug aparece exatamente o tamanho do report.

    • andrealveslima disse:

      Olá Bruno!

      Que estranho.. Nunca tive esse tipo de problema.. Será que não está com algum problema na margem? Se quiser mandar o rdlc (ou o projeto) para eu dar uma testada aqui, fique à vontade.. Meu e-mail é o contato [arroba] andrealveslima [ponto] com [ponto] br

      Abraço!
      André Lima

      • Bruno disse:

        André, muito obrigado. Pelo debug percebi que a imagem não renderizava com a página em modo paisagem. Na hora da geração de imagem, passei a verificar qual o formato em que ela se encontrava para inverter os valores de width e height. A partir dessa mudança funcionou normalmente. Pode ser que exista outra forma pra ajustar isso, mas como no momento foi a única que encontrei – resolveu.

        • andrealveslima disse:

          Maravilha, hein Bruno.. Que bom que você conseguiu resolver.. :)

          Qualquer outra dificuldade, é só entrar em contato..

          Abraço!
          André Lima

  • Franco Forno disse:

    Andre, buen dia

    Me fue de gran utilidad el proyecto de ejemplo para probar la impresion directa del report viewer. Precisaria de tu asesoramiento ya que preciso incluir un codigo de barras en el report viewer para imprimirlo de forma directa.

    Utilice el siguiente tutorial para generar el codigo de barra y enviarlo como imagen al report viewer

    http://www.andrealveslima.com.br/blog/index.php/2017/11/08/trabalhando-com-codigo-de-barras-no-report-viewer/

    No logro replicar esto para la impresion directa.

    Saludos

    Franco

    • andrealveslima disse:

      Olá Franco!

      Muito obrigado pelo comentário.. Eu respondi o e-mail que você me mandou.. Não entendi muito bem a sua dúvida, mas vamos continuar a conversa por lá.. Fico aguardando o seu retorno..

      Abraço!
      André Lima

  • Renato disse:

    Olá André, primeiramente parabéns pelo post e vídeo aula, te sigo no youtube e acompanho seu post, são de grande ajuda.

    Gostaria de tirar uma duvida com você, como que faz para passar o parâmetro na hora da visualização e impressão.

    Exemplo: No dataset o select precisa de um parâmetro para exibir os dados corretamente, na exibição do reportview normal, eu costumo passar desta forma:

    this.reciboTableAdapter.Fill(this.Data_relatório.recibo,id);

    Saberia me falar como ficaria passando na hora de imprimir sem a visualização?

    Obrigado.
    Abraço!

    • andrealveslima disse:

      Olá Renato, muito obrigado pelo comentário!

      Nesse caso, na realidade você está passando o parâmetro para o método “Fill” do DataAdapter, que a princípio é independente do relatório.. Repare no exemplo do vídeo que eu passo os dados para o relatório na linha com a chamada “relatorio.DataSources.Add…”.. Nesse exemplo eu estou passando a DataTable “Item” que foi preenchida pelo método “CriarDataSet”.. No seu caso, você vai passar a sua DataTable “recibo”, que foi preenchida pelo método “Fill” anteriormente utilizando o parâmetro indicado..

      Entendeu a ideia? O parâmetro do método “Fill” do Adapter é independente do relatório..

      Abraço!
      André Lima

      • Renato disse:

        Olá André, obrigado por responder. Entendi a ideia.
        Fiz igual a você criei um DataTable e deu certo.
        Porem agora surgiu uma outra dúvida…rsrs
        Como que eu passo um parâmetro normal, por aqui:

        var ds = CriarDataSet();
        FormRelatorio.ShowReport(“Relatorio.rdlc”, false, new Dictionary() { { “DataSetRelatorio”, (DataTable)ds.Item } });
        }

        Para cair corretamente neste método:
        // reportParameters.
        if (reportParameters != null)
        {
        var reportParameterCollection = new List();

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

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

        Obrigado

        • andrealveslima disse:

          Olá Renato!

          É só passar as combinações de chave/valor no quarto parâmetro da chamada.. Exemplo:

          FormRelatorio.ShowReport("Relatorio.rdlc", false, new Dictionary() { { "DataSetRelatorio", (DataTable)ds.Item } }, , new Dictionary() { { "Parametro1", "ValorParametro1" }, { "Parametro2", "ValorParametro2" } });
          

          Abraço!
          André Lima

  • Raul Kalandula disse:

    Boa noite caríssimo André Alves Lima, tenho um leitor Biométrico SDK da Nitgen, mas infelizmente não consigo fazer o cadastro das impressões digitais no SQL Server e para posteriormente fazer o login. Estou usando o Visual Studio (Visual Basic)

    • andrealveslima disse:

      Olá Raul!

      Infelizmente vou ficar te devendo essa.. Não tenho nenhum dispositivo biométrico aqui para poder testar, então fica difícil ajudar.. Mas, normalmente os fabricantes dos dispositivos têm exemplos para download em diversas linguagens.. Você já deu uma procurada para ver se não acha um exemplo pronto em .NET?

      Abraço!
      André Lima

  • Kayo Alves disse:

    Olá André, estou tendo problema em gerar um relatório com a propriedade EnableExternalImages… No relatório, apenas visualizando, funciona normalmente. Nas propriedades dele já está habilitado esta questão da imagem. Porém ao passar pra toda essa metodologia de imprimir direto; dá erro dizendo que a propriedade das imagens externas está desabilitado. Coloquei no método CriarDeviceInfo a linha: relatorio.EnableExternalImages = true; que resolve este erro e passa a ser outro:

    na linha relatorio.Render(“image”…..); dá o seguinte erro:
    ReportProcessingException: Não é possível criar um leitor de dados para o conjunto de dados ‘MeuDataSet’.

    Penso que falta eu acrescentar alguma linha no xml do device info… Já viu este erro?

    Muito obrigado.

    • Kayo Alves disse:

      Oi André, o problema foi resolvido, estava ainda vacilando com os nomes dos datasets. Tem um que a gente nomeia quando cria uma fonte de dados, este é o nome pra se usar na definição… Mais uma vez obrigado. A questão das imagens externas além da definição no próprio RDLC, tem que apenas inserir esta linha que inseri e já resolve o problema de dar erro.
      CriarDeviceInfo(…)
      relatorio.EnableExternalImages = true;
      Forte abraço.

      • andrealveslima disse:

        Olá Kayo!

        Obrigado pelo retorno.. Fico feliz que você tenha conseguido solucionar o problema.. E obrigado pelo toque referente à propriedade “EnableExternalImages”..

        Abraço!
        André Lima

  • Jorge Kharuf disse:

    André, Parabéns pelo post e pela explicação!

    Estava precisando mesmo de criar um de meus relatórios de uma forma direta da impressora.

    Aproveitando, peço uma ajuda sua (tentei de várias forma e não obtive sucesso!).

    É:

    – Tenho um relatório que não é “tipado” onde passo parâmetros para alguns campos. Bom, em um determinado campo, na base de dados, tem vários itens para o do cliente que está sendo impresso.

    Pergunto (dúvida):
    Como faço para passar o parâmetro para esses itens?
    Para ser mais claro, estou imprimindo uma Ordem de Serviço e é no momento de imprimir os itens de produtos.

    Fico no aguardo de uma ajuda nessa minha dúvida. Ah!, já tenho assinatura da página.

    Desde já, agradeço pelas ótimas “DIKAS”, explicações e vídeos seus!

    Jorge Kharuf

  • Jorge Puga disse:

    Gracias Andres, un abrazo desde Iquitos-Perú, buen video, me pudieras hacer llegar tu proyecto por favor. Gracias

Deixe uma resposta

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