Neste tópico vou mostrar como enviar comandos para uma impressora de etiquetas usando o Código C# do Formulário Dinâmico.
A linguagem utilizada vai depender do suporte oferecido pela impressa:
- ZPL - Zebra Programming Language
- DPL - Datamax Programming Language
- EPL – Eltron Programming Language
- IPL – Intermec Programming Language
Ou ainda as linguagens de emulação:
- PPLA – Printer Programming Language A
- PPLB – Printer Programming Language B
Infelizmente, eu não tive a oportunidade de executar este código pessoalmente pois não tenho uma impressora de etiquetas para testar, mas ajudei outras pessoas a fazer essa implementação a partir do código que será apresentado aqui, e funcionou!
Exemplo Simples
Primeiro, vamos começar com um exemplo simples: teremos um campo do tipo TextBox com a propriedade “multilinha” habilitada. Neste campo, vamos informar os comandos e clicar em um campo do tipo Button para enviá-los à impressora.
Campos
-
txtComando - Campo do tipo TextBox e com a propriedade “multilinha” habilitada
-
btnExecutar - Camo do tipo Button, que quando clicado vai enviar o comando para a impressora.
Variáveis
-
ip - Variável do tipo Text que receberá o IP da impressora na rede.
-
porta - Variável do tipo Number que receberá a Porta da impressora.
-
temperatura - Variável do tipo Text que receberá a temperatura que será usada na impressão, no formato especificado pelo fabricante.
Procedimentos
-
btnExecutar_Click - Procedimento que será vinculado ao evento Click do botão btnExecutar.
- Neste procedimento, vamos preencher as variáveis e em seguida executar o código C# descrito no próximo item.
Código C#
O código C# abaixo deve ser executado através da ação “Executar Código C#” no procedimento “btnExecutar_Click”:
using System.Data.Common;
using LATROMI.Extensions;
var ip = (string)Variables["ip"].Value;
var porta = (int)Variables["porta"].Value;
var temperatura = (string)Variables["temperatura"].Value;
var comando = (string)Fields["txtComando"].Value;
if (string.IsNullOrEmpty(ip))
throw new InvalidOperationException("Impressora não informada.");
if (string.IsNullOrEmpty(temperatura))
throw new InvalidOperationException("Temperatura não informada.");
if (string.IsNullOrEmpty(comando))
throw new InvalidOperationException("Informe um comando para enviar para a impressora.");
using (var client = new System.Net.Sockets.TcpClient())
{
var serverEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse(ip), porta);
client.Connect(serverEndPoint);
using (var clientStream = client.GetStream())
{
var encoder = new System.Text.ASCIIEncoding();
byte[] buffer = encoder.GetBytes(comando);
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
}
Pronto! Informando o código corretamente, deve ser possível realizar a impressão.
Exemplo Avançado
No exemplo anterior, implementamos uma rotina simples, mas que é útil para testes.
Agora, vamos implementar um cenário mais próximo da realidade, aplicável a um ambiente de produção.
Considerando que ainda teremos as mesmas variáveis vamos implementar um código C# com o seguinte objetivo:
-
Executar um
SELECT
no banco de dados e retornar os dados que serão plotados na impressão. -
Percorrer cada registro retornado e montar o código de impressão referente a cada um.
-
Após acumular 20 comandos de impressão, vamos enviá-los para uma fila para serem enviados para impressora no final do processo. Esses 20 comandos serão enviados de uma só vez para a impressora. Você pode “granular” esses comandos em uma quantidade maior ou menor. A intenção é não enviar uma quantidade de comandos tão grande que possa travar ou causar um Timeout.
-
Depois que terminar de percorrer todos os registros, vamos enviar os comandos da fila uma a um para a impressora.
Vamos lá!
using System.Data.Common;
using LATROMI.Extensions;
// Dicionário que vai receber os valores das colunas do registro retornado pelo SQL
var rDados = new Dictionary<string, object>();
var ip = (string)Variables["ip"].Value;
var porta = (int)Variables["porta"].Value;
var temperatura = (string)Variables["temperatura"].Value;
// Fila de comandos
var printQueue = new Queue<string>();
// Quantidade de comandos que serão enviados de uma só vez para a impressora
int stepSize = 20;
if (string.IsNullOrEmpty(ip))
throw new InvalidOperationException("Impressora não informada.");
if (string.IsNullOrEmpty(temperatura))
throw new InvalidOperationException("Temperatura não informada.");
// Select para buscar os dados que serão impressos
var cmdText = new StringBuilder();
cmdText.AppendLine("SELECT");
cmdText.AppendLine("*");
cmdText.AppendLine("FROM tabela");
cmdText.AppendLine("WHERE id = 123456");
// NOTA: Passar o nome da conexão do LATROMI como parametro no método Database.CreateConnection("_______")
using (var connection = Database.CreateConnection("Nome da minha conexão no LATROMI"))
{
// Abre a conexão
connection.Open();
// Percorre todos os registros e monta os comandos que seram enviados à impressora
using(var cmd = connection.CreateCommand())
{
cmd.CommandText = cmdText.ToString();
using (var dr = cmd.ExecuteReader())
{
int fieldCount = dr.FieldCount;
while (dr.Read())
{
// Copia todos os valores do DataReader para o dicionário
for (int i = 0; i < fieldCount; i++)
{
rDados.Add(
dr.GetName(i),
Convert.IsDBNull(dr.GetValue(i)) ? null : dr.GetValue(i)
);
}
// Exemplo de comando DPL meramente ilustrativo. Informe outro código.
// NOTA: Para informar caracteres especiais basta converter o número
// da tabela ascii para "char" como nas 3 primeiras linhas
var dataToSend = new StringBuilder()
.AppendLine(((char)2).ToString() + "n")
.AppendLine(((char)2).ToString() + "f000")
.AppendLine(((char)2).ToString() + "L")
.AppendLine("H" + temperatura)
.AppendLine("...")
.AppendLine("..." + rDados["select_campo1"])
.AppendLine("..." + rDados["select_campo2"])
.AppendLine();
// Adiciona na fila
printQueue.Enqueue(dataToSend.ToString());
// Limpa o dicionário com os campos
rDados.Clear();
}
dr.Close();
}
}
// Percorre a lista com os comandos a serem enviados para a impressora
while (printQueue.Any())
{
using (var client = new System.Net.Sockets.TcpClient())
{
var serverEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse(ip), porta);
client.Connect(serverEndPoint);
using (var clientStream = client.GetStream())
{
for (int i = 0; i < stepSize; i++)
{
// Remove da fila e envia para impressora
var encoder = new System.Text.ASCIIEncoding();
byte[] buffer = encoder.GetBytes(printQueue.Dequeue());
clientStream.Write(buffer, 0, buffer.Length);
// Se não tiver mais nada para imprimir, cai fora
if (!printQueue.Any()) break;
}
clientStream.Flush();
}
}
}
}
Experiência do Usuário
Para melhorar a experiência do usuário, podemos implementar uma tela de espera, pois dependendo do volume de dados a impressão pode demorar.
Para implementar a tela de espera, dê uma olhada neste tópico: