12Druckaufträge & Massendruck
Ein Druckauftrag ist ein ZPL-Strom: optional ein Vorlauf-Etikett, ein Etikett pro Datensatz und optional ein Nachlauf-Etikett. Mit CutAfterLastLabel() läuft der ganze Auftrag im Abreißmodus und nur nach dem letzten Etikett wird geschnitten.
Vorlauf, Nachlauf und Schnitt (LabelBinding)
// Vor- und Nachlauf-Etikett werden an PrintJobInfo gebunden:
// JobName, Created, RecordCount, LabelCount, FirstKey, LastKey
var leading = new Label(LabelUnit.Mm, 100, 60)
.Add(new TextItem { X = 5, Y = 5, Text = "DRUCKAUFTRAG", FontSize = 22 })
.Add(new TextItem { X = 5, Y = 20, DataField = "JobName", FontSize = 14 })
.Add(new TextItem { X = 5, Y = 32, Expression = "Format([Created], \"dd.MM.yyyy HH:mm\")" })
.Add(new TextItem { X = 5, Y = 42, Expression = "[RecordCount] + \" Sendungen\"" });
var trailing = new Label(LabelUnit.Mm, 100, 60)
.Add(new TextItem { X = 5, Y = 5, Text = "ENDE DES AUFTRAGS", FontSize = 18 })
.Add(new TextItem { X = 5, Y = 20, Expression = "[LabelCount] + \" Labels gedruckt\"" })
.Add(new TextItem { X = 5, Y = 30, Expression = "\"von \" + [FirstKey] + \" bis \" + [LastKey]", FontSize = 9 });
var label = new Label(LabelUnit.Mm, 100, 60)
.Add(new TextItem { X = 4, Y = 4, DataField = "Name", FontSize = 14 })
.Add(new TextItem { X = 4, Y = 12, DataField = "City" })
.Add(new BarcodeItem { X = 4, Y = 22, DataField = "TrackingNo", BarHeight = 18 });
string zpl = label.For<Parcel>()
.Job("Versand Wien", p => p.TrackingNo) // Name + Schlüssel für FirstKey/LastKey
.Copies(p => p.Parcels) // LabelCount zählt die Kopien mit
.WithLeadingLabel(leading)
.WithTrailingLabel(trailing)
.CutAfterLastLabel() // 1. Format ^MMT (Abreißen), letztes ^MMC (Schneiden)
.ToZpl(parcels); // Liste → RecordCount schon im Vorlauf bekannt
| Methode / Feld | Bedeutung |
|---|---|
.Job(name, keySelector) | Auftragsname und Schlüssel pro Datensatz (z. B. Sendungsnummer) für FirstKey/LastKey |
.WithLeadingLabel(label) | Vorlauf-Etikett, gebunden an PrintJobInfo |
.WithTrailingLabel(label) | Nachlauf-Etikett mit Summen, gebunden an PrintJobInfo |
.CutAfterLastLabel() | erstes Format bekommt ^MMT (Abreißen, gilt für alle folgenden), nur das letzte Format ^MMC (Schneiden) |
PrintJobInfo.JobName, Created | Name und Erstellzeit des Auftrags |
PrintJobInfo.RecordCount | Anzahl Datensätze – im Vorlauf bekannt, wenn eine Liste/Collection übergeben wird; im Nachlauf immer gesetzt |
PrintJobInfo.LabelCount | gedruckte Etiketten inkl. Kopien (Copies) |
PrintJobInfo.FirstKey, LastKey | Schlüssel des ersten und letzten Datensatzes |
Alle Felder sind als DataField oder in Ausdrücken ([RecordCount] + " Sendungen") nutzbar. Das Ergebnis für drei Sendungen (eine davon mit zwei Kopien): 5 Formate, 6 Etiketten.
Vorlauf

Datensatz 2 (^PQ2)

Nachlauf (^MMC)

Erzeugtes ZPL anzeigen
PrintJobTemplate: ein Auftrag aus JSON-Vorlagen
PrintJobTemplate fasst Vorlauf-, Datensatz- und Nachlauf-Etikett samt Optionen zusammen. Laden aus drei Label-Vorlagen (FromFiles(leading, label, trailing), Vor-/Nachlauf optional) oder aus einer JSON-Datei (ToJson/FromJson); SaveFiles zerlegt wieder in drei Dateien. For<T>() liefert die fertig konfigurierte LabelBinding<T>.
// drei JSON-Vorlagen (z. B. aus einem Designer) → EIN Druckauftrag
var job = PrintJobTemplate.FromFiles("templates/leading.json", "templates/shipping.json", "templates/trailing.json");
job.JobName = "Tagesversand";
job.CutAfterLastLabel = true; // nur nach dem Nachlauf-Etikett schneiden
job.StoredFormatName = "R:SHIP.ZPL"; // Vorlage einmal per ^DF, danach nur ^XF + ^FN-Werte
job.KeyField = "TrackingNo"; // FirstKey/LastKey im Nachlauf
job.CopiesField = "Parcels"; // ^PQ pro Datensatz
string zpl = job.For<Shipment>().ToZpl(shipments.ToList());
// derselbe Auftrag als EINE JSON-Datei – oder wieder in drei Dateien zerlegt
File.WriteAllText("printjob.json", job.ToJson());
PrintJobTemplate same = PrintJobTemplate.FromJson(File.ReadAllText("printjob.json"));
same.SaveFiles("leading.json", "shipping.json", "trailing.json");
| Option | Wirkung |
|---|---|
JobName | Name für PrintJobInfo.JobName (Standard „Druckauftrag“) |
CutAfterLastLabel | ^MMT für alle, ^MMC nur für das letzte Etikett |
StoredFormatName | Datensatz-Etikett einmal per ^DF speichern, dann nur ^XF + ^FN |
KeyField | Property-Pfad für FirstKey/LastKey |
CopiesField | Property-Pfad für die Kopienzahl pro Datensatz |
leading.json (Auszug)
printjob.json – alles in einer Datei (Auszug)
Vorlagen: leading.json · shipping.json · trailing.json · printjob.json
Massendaten-Demo: EF Core + LiteDB → eine .zpl-Datei
samples/MassDataDemo lädt die drei Vorlagen, fragt 50 Sendungen per LINQ aus SQLite (EF Core) bzw. LiteDB ab und schreibt jeweils einen Auftrag: Vorlauf, ^DF-Vorlage, 50 Versandetiketten, Nachlauf, Schnitt.
// samples/MassDataDemo: 50 Versandetiketten + Vorlauf + Nachlauf + Schnitt in EINER .zpl-Datei
var job = PrintJobTemplate.FromFiles("templates/leading.json", "templates/shipping.json", "templates/trailing.json");
job.CutAfterLastLabel = true; // Abreißen für alle, Schnitt nach dem Nachlauf-Etikett
job.KeyField = "TrackingNo"; // erste/letzte Sendungsnummer im Nachlauf
// ---------- EF Core + SQLite ----------
using var connection = new SqliteConnection("Data Source=:memory:");
connection.Open();
var options = new DbContextOptionsBuilder<ShippingDb>().UseSqlite(connection).Options;
using var db = new ShippingDb(options);
db.Database.EnsureCreated();
db.Shipments.AddRange(seedData);
db.SaveChanges();
var query = db.Shipments.AsNoTracking() // von SQLite ausgeführt
.Where(s => !s.Printed && s.Service == "EXPRESS")
.OrderByDescending(s => s.Id)
.Take(50);
job.JobName = "EF Core · Express";
job.StoredFormatName = "R:SHIP.ZPL"; // Vorlage einmal, dann nur Feldwerte
string efZpl = job.For<Shipment>()
.Map("Total", s => s.WeightKg.ToString("0.0") + " kg")
.ToZpl(query.ToList());
File.WriteAllText("massdata-efcore.zpl", efZpl);
// ---------- LiteDB ----------
using var lite = new LiteDatabase(new MemoryStream());
var col = lite.GetCollection<Shipment>("shipments");
col.InsertBulk(seedData);
col.EnsureIndex(s => s.Country);
var docs = col.Query().Where(s => s.Country == "AT").OrderBy(s => s.TrackingNo).Limit(50).ToEnumerable();
job.JobName = "LiteDB · Österreich";
job.StoredFormatName = null; // volles Format pro Etikett
string liteZpl = job.For<Shipment>()
.Map("Total", s => s.WeightKg.ToString("0.0") + " kg")
.ToZpl(docs.ToList());
File.WriteAllText("massdata-litedb.zpl", liteZpl);
// Vorschau des ganzen Auftrags als PDF
var renderer = new ZplRenderer(new ZplRenderSettings { OutputFormat = ZplOutputFormat.Pdf }.WithLabelSizeMm(100, 150));
File.WriteAllBytes("massdata-efcore.pdf", renderer.ProcessCommands(efZpl)[0]);
dotnet run --project samples/MassDataDemo -- samples/output samples/templates
Vorlauf (^MMT)

Versandetikett 1 von 50

Nachlauf (^MMC)

massdata-efcore.zpl (Auszug)
^DF/^XF) · massdata-efcore.pdf · massdata-litedb.zpl (17 KB, volle Formate) · massdata-litedb.pdf – je 52 Etiketten.Mehr dazu auf zplCloud.com: Vorlage: Versandetikett · Vorlage: Versandlabel 100 × 150 mm mit GS1-128-SSCC

