C# - Imprimindo o conteúdo de um ListBox


 Neste artigo vou mostrar como imprimir o conteúdo exibido em um controle ListBox usando os recursos de impressão da plataforma .NET e a linguagem C#.

O controle ListBox deriva da classe ListControl que é uma classe abstrata e não pode ser instanciada , mas as classes concretas citadas e delas derivadas podem ser instanciadas e usadas normalmente conforme veremos a seguir.

A classe ListControl fornece muito das funcionalidades comuns entre estes três controles. A tabela abaixo lista as cinco propriedades nativas da classe ListControl que são herdadas pelas classes derivadas.

Propriedades da classe ListControl

Propriedade Tipo Descrição
DataSource Object Read/write. Define a fonte de dados para o controle de lista
DisplayMember String Read/write. Define a propriedade da fonte de dados a ser exibida no controle.
SelectedValue Object Read/write. Contém o valor do item selecionado atual definido pela propriedade ValueMember. Se ValueMember nao estiver definido retorna : object.ToString( ).
ValueMember String Read/write. Define a propriedade da fonte de dados retornada pela propriedade SelectedValue.  Pode ser anulada atribuindo uma string vazia ou uma referencia Null.
SelectedIndex Integer Read/write. O indice baseado no valor inicial zero do item atualmente selecionado. O valor -1 indica que nenhum item esta selecionado.

Estas propriedades incluem a propriedade DataSource e muitas propriedades úteis . Nas tabelas a seguir temos as propriedades/métodos que não são membros da classe ListControl mas são membros para todos os três controles derivados desta classe. Elas incluem propriedades para definir a aparência do controle e propriedades relacionadas com a coleção de itens dos controles.

Propriedades comum a todos os controles de lista

Propriedade tipo Descrição
IntegralHeight Boolean Read/write. Se True (o padrão) o controle se redimensiona para evitar mostrar itens parciais.
DrawMode DrawMode Read/write. Define o modo de desenho para o controle. Os valores válidos são:
- DrawMode.Normal (padrão), DrawMode.OwnerDrawFixed, and DrawMode.OwnerDrawVariable.
ItemHeight Integer Read/write. Altura de um item no controle em pixels.
Items ObjectCollection Read-only. Coleção de itens no controle.
PreferredHeight Integer Read-only. A altura de todos os itens no controle em pixels. Esta é a altura que o controle precisa para exibir todos os itens se efetuar uma rolagem vertical.
SelectedItem Object Read/write. O item atualmente selecionado no controle.
Sorted Boolean Read/write. Se false (o padrão), os itens no controle não estão ordenados e novos itens são incluídos no final da lista. De outra forma eles são ordenados em ordem crescente , em ordem alfabética , e case-insensitive. Se True ,  o indice de um item especifico pode ser alterado conforme novos itens forem sendo incluídos.
Text String Read/write. O texto associado ao item atualmente selecionado.

Métodos comum a todos os controles de lista

Método Descrição
BeginUpdate Evita o redesenho do controle enquanto itens são incluídos na coleção de itens.
EndUpdate Recupera o desenho do controle depois que BeginUpdate foi invocado.
FindString Overloaded. Retorna um índice baseado em zero do primeiro item na coleção de itens que inicia com uma string definida.
FindStringExact Overloaded. Retorna um índice baseado em zero do primeiro item da coleção deitens que coincide exatamente com a string definida

Imprimindo com PrintDocument

Imprimir textos e gráficos é uma das muitas tarefas que um programador tem que realizar em uma aplicação Windows Forms. Enviar um texto para a impressora é muito simples , mas a plataforma .NET não fornece os recursos de impressão para tarefa mais complexas como configurar uma impressora ou uma página para impressão, definir margins e imprimir mais que uma cópia. Neste aspecto a Microsoft ficou devendo...

Neste artigo eu vou apresentar uma breve introdução sobre como efetuar a impressão com as classes da .NET Framework usando a linguagem C#. Para fornecer as funcionalidades básicas para imprimir em aplicações Windows Forms devemos estar familiarizados com a classe Graphics do namespace System.Drawing.

Para imprimir usamos o namespace System.Drawing.Printing onde a classe principal é a classe PrintDocument que representa um objeto que envia a saída para a impressora.

Para imprimir um texto ou um gráfico chamamos o método Print da classe PrintDocument e um dos eventos que o método Print invoca é o evento PrintPage. (Você precisa vincular um manipulador de evento a este evento e escrever o código para enviar a saída para a impressora. )

O manipulador de eventos irá receber um argumento do tipo PrintPageEventArgs contendo os dados relacionados ao evento PrintPage e uma das propriedades deste argumento é a propriedade Graphics a partir da qual você pode obter um objeto Graphics.

Este objeto Graphics representa uma página a ser impressa e para enviar uma string para a impressora, por exemplo, você pode usar o método DrawString da classe Graphics. Você pode chamar outros método desta classe como FillRectangle, DrawEllipse, etc.

Para ilustrar como imprimir usando os membros do namespce System.Drawing.Printing vamos usar um exemplo simples onde mostrarei como usar os recursos de impressão usando C#.

Nota : Para saber como usar o controle ListBox e o objeto PrintDocument leia os artigos citados nas referências.

Recursos usados :

Criando o projeto no VS Community 2015

Abra o VS Community e clique em New Project;

Selecione a linguagem Visual C# e o template Windows Forms Application;

Informe o nome da solução como Imprimir_ListBox clique no botão OK;

A partir da ToolBox inclua no formulário form1.cs os controles :

Disponha os controles conforme o leiaute da figura abaixo:

Defina os seguintes namespaces no formulário:

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

No início do formulário defina a variável privada meuLeitor:

private StringReader meuLeitor;

Imprimindo o conteúdo do ListBox

No evento Load do formulário vamos definir o código para preencher o ListBox a partir de uma lista de strings:

 private void Form1_Load(object sender, EventArgs e)
 {
            string[] nomes = new string[12];
            nomes[0] = "Macoratti";
            nomes[1] = "Jefferson";
            nomes[2] = "Janice";
            nomes[3] = "Jessica";
            nomes[4] = "Miriam";
            nomes[5] = "Marcia";
            nomes[6] = "Irene";
            nomes[7] = "Yuri";
            nomes[8] = "Bianca";
            nomes[9] = "Igor";
            nomes[10] = "Larissa";
            nomes[11] = "Giovana";
            lbDados.Items.AddRange(nomes);
  }

Para habilitar/Desabilitar o botão - Carregar Dados - vamos definir no evento CheckedChanged do controle chkBD o código abaixo:

 private void chkBD_CheckedChanged(object sender, EventArgs e)
  {
            btnCarregarDados.Enabled = chkBD.Checked;
  }

No evento Click do botão Carregar dados temos o código para preencher o controle ListBox a partir de um banco de dados.

No exemplo eu acessando a tabela Products do banco de dados Northwind.mdf e exibindo apenas o nome do produto no listbox:

   private void btnCarregarDados_Click(object sender, EventArgs e)
   {
            try
            {
                SqlConnection conn = new SqlConnection(@"Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True");
                conn.Open();
                DataSet ds = new DataSet();
                SqlDataAdapter adapter = new SqlDataAdapter("SELECT ProductId, ProductName from Products", conn);
                adapter.Fill(ds, "Products");
                lbDados.ValueMember = "ProductId";
                lbDados.DisplayMember = "ProductName";
                lbDados.DataSource = ds.Tables["Products"];
            }
            catch (Exception ex)
            {
                MessageBox.Show("Erro " + ex.Message, "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
  }

Agora para imprimir vamos precisar definir o código abaixo no evento PrintPage do componente PrintDocument:

        private void pd1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
        {
            //define as variáveis para controlar as linhas, o posicionamento e a caneta e cor usada
            float linhasPorPagina = 0;
            float yPosicao = 0;
            int contador = 0;
            float MargemEsquerda = e.MarginBounds.Left;
            float MargemTopo = e.MarginBounds.Top;
            string linha = null;
            // define a fonte e a pena e sua cor
            Font FonteImpressao = this.lbDados.Font;
            SolidBrush minhaPena = new SolidBrush(Color.Black);
         
            // Define o numero de linhas por pagina usando MarginBounds.
            linhasPorPagina = e.MarginBounds.Height / FonteImpressao.GetHeight(e.Graphics);
            // Percorre a string usando o StringReader e imprime cada linha
            while (contador < linhasPorPagina && ((linha = meuLeitor.ReadLine()) != null))
           {
                // calcula a posição da proxima linha com base na
                // altura da fonte de acordo com o dispositivo de impressão
                yPosicao = MargemTopo + (contador * FonteImpressao.GetHeight(e.Graphics));
                // desenha a proxima alinha no controle 
                e.Graphics.DrawString(linha, FonteImpressao, minhaPena, MargemEsquerda, yPosicao, new StringFormat());
                contador++;
            }
            // Se existe mais linhas imprime outra pagina
            if (linha != null)
                e.HasMorePages = true;
            else
                e.HasMorePages = false;
                minhaPena.Dispose();
   }

Agora só falta definir o código no evento Click do botão Imprimir.

Aqui temos que verificar qual a fonte de dados foi usada para preencher o listbox. Se foi um banco de dados então temos que converter os itens do ListBox para string, caso contrário será impresso o texto System.Data.DataRowView.

     private void btnImprimir_Click(object sender, EventArgs e)
     {
            printDialog1.Document = pd1;
            string strTexto = "";
            //Se a fonte é um banco de dados 
            if (chkBD.Checked)
            {
                //percorre cada item e converte para string
                for (int i = 0; i < lbDados.Items.Count-1; i++)
                {
                        DataRowView drv = (DataRowView)lbDados.Items[i];
                        String elemento = drv["ProductName"].ToString();
                        strTexto = strTexto + elemento.ToString() + "\n";
                }
            }
            else
            {
                foreach (object x in lbDados.Items)
                {
                        strTexto = strTexto + x.ToString() + "\n";
                }
            }         
            meuLeitor = new StringReader(strTexto);
            if (printDialog1.ShowDialog() == DialogResult.OK)
            {
                 this.pd1.Print();
            }
   }

Agora é só alegria...

Nota: Para não gastar papel eu estou imprimindo para um arquivo PDF.

1- Testando a impressão para o listbox com fonte de dados não sendo um banco de dados temos:

Foi gerado o arquivo documento1.pdf com o seguinte conteúdo exibido no Adobe Reader :

2- Testando a impressão para o listbox com fonte de dados a partir de um banco de dados (tabela Products) temos:

Será gerado o arquivo PDF documen2t.pdf com o seguinte conteúdo exibido no Adobe Reader:

Pegue o projeto completo aqui :  Imprimir_ListBox.zip

E esta é a mensagem que dele (Jesus) ouvimos, e vos anunciamos: que Deus é luz, e não há nele trevas nenhumas.
Se dissermos que temos comunhão com ele, e andarmos em trevas, mentimos, e não praticamos a verdade.

1 João 1:5,6

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Referências:


José Carlos Macoratti