LabelBinding<T>
public sealed class LabelBinding<T>Strongly typed, streaming mass data binding of a Label to C# objects. Works with anything enumerable: lists, LINQ queries, EF Core IQueryable (sync) or AsAsyncEnumerable() (async), so millions of records never have to be in memory at once.
Thread safety: once configured, ToZpl/Generate/Render may be called from several threads concurrently (the label template is only read); configuration methods (Map, Copies, ...) are not thread-safe.
Methods
| Method Signature | Returns | Description |
|---|---|---|
# Across(int columns, double gap = 0, double leftOffset = 0) | LabelBinding<T> | Multi-across media: places columns records side by side in one format (e.g. 3 labels per row on 100 mm wide liner), separated by gap (label units). |
# Batches(IEnumerable<T> records, int labelsPerBatch = 500, int dpi = 203) | IEnumerable<string> | Groups the generated ZPL into batches of labelsPerBatch records (one network write each). |
# Copies(Func<T, int> copies) | LabelBinding<T> | Number of printed copies per record (^PQ), e.g. o => o.Quantity. |
# CountQueryableWith(Func<IQueryable<T>, int> counter) | LabelBinding<T> | Counts IQueryable sources before streaming, e.g. q => q.Count() (one extra COUNT query; the records themselves are enumerated only once). |
# CutAfterLastLabel(bool cut = true) | LabelBinding<T> | Cut only after the last label of the job: all formats print in tear-off mode (^MMT), the last one in cutter mode (^MMC). Default: Label.CutAfterLastLabel. |
# Generate(IEnumerable<T> records, int dpi = 203) | IEnumerable<string> | Lazily yields ZPL: leading label, ^DF template, one format per record, trailing label. |
# Generate(IEnumerable<T> records, int dpi, int? recordCount) | IEnumerable<string> | Like LabelBinding.Generate with an explicit record count (null = automatic). |
# GenerateAsync(IAsyncEnumerable<T> records, int dpi = 203, CancellationToken ct = default) | IAsyncEnumerable<string> | Async counterpart of LabelBinding.Generate for streamed sources (database readers, APIs). |
# GenerateAsync(IAsyncEnumerable<T> records, int dpi, int? recordCount, CancellationToken ct = default) | IAsyncEnumerable<string> | Async generation with a known record count (e.g. from a separate COUNT query) for the leading label and TOTAL_PAGES. |
# Job(string name, Func<T, string>? key = default) | LabelBinding<T> | Name and key (e.g. tracking number) used for PrintJobInfo. |
# Map(string field, Func<T, object> selector) | LabelBinding<T> | Binds a data field name (as used in LabelItem.DataField or [Name] in expressions) to a lambda. |
# MapItem(string itemName, Func<T, object> selector) | LabelBinding<T> | Binds the item with the given LabelItem.Name to a lambda (sets its DataField to the name). |
# OnProgress(Action<LabelProgress> progress) | LabelBinding<T> | Called once per printed label of the records (copies included; not for leading/trailing labels), in label order, when the label's format is handed out – also when formats are built in parallel. Runs on the thread that enumerates the job (LabelBinding.Generate, ToZpl, Write, Print, Render), so keep it short. |
# PrintAsync(ZplPrinterClient printer, IAsyncEnumerable<T> records, int labelsPerBatch = 500, int dpi = 203, IProgress<int>? progress = default, CancellationToken ct = default) | Task<int> | Prints all records in batches over one connection per batch. Returns the number of records. |
# PrintAsync(ZplPrinterClient printer, IEnumerable<T> records, int labelsPerBatch = 500, int dpi = 203, IProgress<int>? progress = default, CancellationToken ct = default) | Task<int> | Prints all records in batches (record count known up front). Returns the number of records. |
# PrintAsync(ZplPrinterClient printer, IAsyncEnumerable<T> records, int? recordCount, int labelsPerBatch = 500, int dpi = 203, IProgress<int>? progress = default, CancellationToken ct = default) | Task<int> | Prints an async source with a known record count (leading label, TOTAL_PAGES). |
# Render(IEnumerable<T> records, int dpi = 203, ZplOutputFormat format = ZplOutputFormat.Png) | IEnumerable<byte[]> | Lazily renders one encoded image per printed label (preview, PDF archive, e-mail ...). The leading items that are the same on every label (captions, frames, logos – up to the first item that varies) are rasterised once per job and every label is drawn over that image: the same pixels as rendering each label on its own. |
# RenderPdf(IEnumerable<T> records, int dpi = 203) | byte[] | All labels as one multi-page PDF. |
# RenderPdf(IEnumerable<T> records, int dpi, int imageQuality) | byte[] | All labels as one multi-page raster PDF with the given image quality: 101 = lossless, 1–100 = JPEG (see ZplRenderSettings.PdfImageQuality). |
# ToZpl(IEnumerable<T> records, int dpi = 203) | string | Generates ZPL for all records (fine for small/medium jobs; use the Write/Stream methods for big ones). |
# UseStoredFormat(string name = "R:ZPLCORE.ZPL") | LabelBinding<T> | Stores the label once in printer memory (^DF) and sends only the variable field values per record (^XF/^FN). Cuts the data volume for large jobs by typically 80–95 %. |
# WithCulture(string culture) | LabelBinding<T> | Culture for {t:key} placeholders of this job (overrides Label.Culture). |
# WithLeadingLabel(Label label) | LabelBinding<T> | Label printed before the records (bound to PrintJobInfo: JobName, Created, RecordCount if known, …). |
# WithParallelism(int maxDegree) | LabelBinding<T> | Formats of a job are built on up to maxDegree threads at once, in blocks of records; the output order, counters and job information stay exactly as in sequential generation (1 = sequential). Default: all processors for record types whose fields are read without caller code – dictionaries (also JSON-like nested values), JsonElement, JsonNode, DataRow, strings and primitives – and no caller code in the job (LabelBinding.Map functions, custom expression functions, type references, a custom clock). Classes (POCOs) are read through their property getters, which may load data lazily (e.g. Entity Framework proxies sharing one DbContext): those jobs are sequential unless set here. |
# WithRecordCount(int? count) | LabelBinding<T> | Known number of records for streamed sources (shown on the leading label as RecordCount and available as TOTAL_PAGES). Collections are counted automatically; an explicit count passed to Generate/Write overrides this. |
# WithTrailingLabel(Label label) | LabelBinding<T> | Label printed after the records (bound to PrintJobInfo incl. RecordCount, LabelCount, FirstKey, LastKey). |
# WriteZpl(IEnumerable<T> records, TextWriter writer, int dpi = 203) | void | Streams ZPL for all records to a writer (file, network stream ...). |
# WriteZplAsync(IAsyncEnumerable<T> records, TextWriter writer, int dpi = 203, CancellationToken ct = default) | Task | Streams ZPL from an async source, e.g. EF Core query.AsAsyncEnumerable(). |
# WriteZplAsync(IAsyncEnumerable<T> records, TextWriter writer, int dpi, int? recordCount, CancellationToken ct = default) | Task | Streams ZPL from an async source; recordCount (if known) is shown on the leading label and as TOTAL_PAGES. |
# WriteZplAsync(IAsyncEnumerable<T> records, Stream stream, int dpi = 203, int? recordCount = default, CancellationToken ct = default) | Task | Writes UTF-8 ZPL for an async source to a stream with asynchronous writes only (safe for ASP.NET Core Response.Body, which forbids synchronous IO). |
# WriteZplAsync(IEnumerable<T> records, Stream stream, int dpi = 203, int? recordCount = default, CancellationToken ct = default) | Task | Writes UTF-8 ZPL for a (sync) source to a stream with asynchronous writes only. The record count is taken from collections automatically. |
# WriteZplAsync(IAsyncEnumerable<T> records, PipeWriter writer, int dpi = 203, int? recordCount = default, CancellationToken ct = default) | Task | Writes UTF-8 ZPL to a PipeWriter (e.g. ASP.NET Core Response.BodyWriter). |
# WriteZplAsync(IEnumerable<T> records, PipeWriter writer, int dpi = 203, int? recordCount = default, CancellationToken ct = default) | Task | Sync-source variant of the PipeWriter overload. |

