Charts and Barcodes
A QR code that opens an invoice online, a Code 128 barcode with an order number on a packing slip and a chart in a quarterly report are frames that TX Text Control places in a document like images. On the server, your code creates barcodes, styles them, puts them into headers, finds and removes the barcodes of loaded documents and exports a barcode as an SVG image. Charts come with their own requirement, which the last section describes.
Barcodes that a mail merge fills with data, including the table of barcode types and the check of values before merging, are the subject of Barcodes in Mail Merge and Reporting. Frames are placed as described in Images.
How Barcodes Work
A barcode in a document consists of two objects:
- TXBarcodeCore holds the barcode itself: its BarcodeType, the encoded text and its appearance. It renders the barcode as SVG and must be initialized with Create before it's used. The Core engine creates barcodes with this class.
- BarcodeFrame places the barcode in the document, with a name, an ID, a size and a position, like an image or a text frame.
ServerTextControl.Barcodes returns the BarcodeCollection of the main text, and headers, footers and text frames have their own, such as HeaderFooter.Barcodes.
Barcodes are saved as barcodes in the TX Text Control format and RTF. Other formats, such as DOCX and PDF, contain an image of the barcode.
A document can combine both kinds of codes. The packing slip of the blog article Enhancing Documents with QR Codes and Barcodes in .NET C#: A Comprehensive Guide, created by a mail merge, has a QR code in its top-right corner and a one-dimensional barcode with the item code in each row of its item table:

Insert a QR Code and a Barcode
The following program writes the heading of an invoice, anchors a dark blue QR code with a link at the right edge and inserts a Code 128 barcode with the invoice number inline with the text:
using System.Drawing;
using TXTextControl;
using TXTextControl.Barcode;
using TXTextControl.DataVisualization;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Text = "Invoice INV-2025-001\r\nScan the code to open the invoice in the customer portal.\r\n";
const string portalLink = "https://www.textcontrol.com";
TXBarcodeCore qrCode = new TXBarcodeCore();
qrCode.Create();
qrCode.BarcodeType = BarcodeType.QRCode;
qrCode.UpperTextLength = portalLink.Length;
qrCode.Text = portalLink;
qrCode.ForeColor = Color.DarkBlue;
BarcodeFrame qrFrame = new BarcodeFrame(qrCode)
{
Name = "portal-link",
Size = new Size(1440, 1440) // 1 x 1 inch in twips
};
// Anchored to the paragraph at the input position, the text flows around it
tx.Barcodes.Add(qrFrame, HorizontalAlignment.Right, -1, FrameInsertionMode.DisplaceText);
TXBarcodeCore invoiceCode = new TXBarcodeCore();
invoiceCode.Create();
invoiceCode.BarcodeType = BarcodeType.Code128;
invoiceCode.UpperTextLength = 12;
invoiceCode.Text = "INV-2025-001";
invoiceCode.ShowText = true;
invoiceCode.AdditionalText = "Invoice number";
invoiceCode.TextAlignment = TextAlignment.Bottom;
// Inline, like a single character, at the input position
tx.Barcodes.Add(new BarcodeFrame(invoiceCode) { Size = new Size(4320, 1080) }, -1);
tx.Save("barcodes.pdf", StreamType.AdobePDF);
}
The code works as follows:
- UpperTextLength is the maximum number of characters, and Text the encoded text. Both throw an
ArgumentExceptionwhen the value isn't valid for the barcode type, so the type is set first. - ForeColor and BackColor are the colors of the code and its background, and Angle rotates it.
- ShowText shows the encoded text of a one-dimensional barcode, and AdditionalText adds a text of your own. TextAlignment puts both texts at the
Bottomor theTop. - BarcodeCollection.Add with an alignment anchors the barcode to the paragraph that contains the text position. For the FrameInsertionMode,
DisplaceText,DisplaceCompleteLines,AboveTheTextandBelowTheTextcan be used.Add(frame, -1)inserts the barcode inline.
Alignment positions the code inside its frame, MiddleCenter by default. BarcodeTypeSettings controls the check value of the types that have one: HasCheckValue adds it, and ShowCheckValue shows it with the text.
Put a QR Code Into the Header
A barcode in the header appears on every page of its section. The following program adds a header and anchors a QR code with the invoice number at its right edge:
using System.Drawing;
using TXTextControl;
using TXTextControl.Barcode;
using TXTextControl.DataVisualization;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Text = "Invoice INV-2025-001";
TXBarcodeCore qrCode = new TXBarcodeCore();
qrCode.Create();
qrCode.BarcodeType = BarcodeType.QRCode;
qrCode.UpperTextLength = 12;
qrCode.Text = "INV-2025-001";
tx.HeadersAndFooters.Add(HeaderFooterType.Header);
HeaderFooter header = tx.HeadersAndFooters.GetItem(HeaderFooterType.Header);
// Shown on every page of the section
header.Barcodes.Add(new BarcodeFrame(qrCode) { Size = new Size(1080, 1080) },
HorizontalAlignment.Right, -1, FrameInsertionMode.AboveTheText);
tx.Save("header-qr-code.pdf", StreamType.AdobePDF);
}
To place a barcode on a single page instead, use the overload with a page number and a location: tx.Barcodes.Add(frame, 1, new Point(8640, 720), FrameInsertionMode.AboveTheText) places it on page 1, relative to the top-left corner of the page. The blog article Using QR Codes in PDF Documents in C# .NET shows further uses of QR codes.
Find and Remove the Barcodes of a Document
The following program lists the barcodes of a document saved in the TX Text Control format and removes the barcode named "portal-link":
using TXTextControl;
using TXTextControl.DataVisualization;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
// Occurs for each barcode of the loaded document
tx.BarcodeCreated += (sender, e) => Console.WriteLine($"Loaded barcode '{e.BarcodeFrame.Name}'");
tx.Load("Documents/barcodes.tx", StreamType.InternalUnicodeFormat);
foreach (BarcodeFrame frame in tx.Barcodes)
{
Console.WriteLine($"'{frame.Name}': {frame.Size.Width} x {frame.Size.Height} twips, text position {frame.TextPosition}");
}
// null if no barcode has this name
BarcodeFrame portal = tx.Barcodes.GetItem("portal-link");
if (portal != null)
{
tx.Barcodes.Remove(portal);
}
tx.Save("barcodes-changed.tx", StreamType.InternalUnicodeFormat);
}
The code works as follows:
- BarcodeCreated occurs for each barcode of a loaded document, but not for barcodes added with
Add. BarcodeDeleted occurs when a barcode is removed withRemove. - BarcodeCollection.GetItem returns a barcode by its name or ID, or
null, and Remove removes it.
BarcodeFrame.Barcode returns the barcode object of a frame. Changes to the barcode aren't shown automatically: call Refresh of the frame after changing it.
Export a Barcode as SVG
A barcode can also be created without a document, for example for a web page or an email. GetSVG returns the barcode as an SVG string:
using System.Drawing;
using TXTextControl.Barcode;
const string portalLink = "https://www.textcontrol.com";
TXBarcodeCore qrCode = new TXBarcodeCore();
qrCode.Create();
qrCode.BarcodeType = BarcodeType.QRCode;
qrCode.UpperTextLength = portalLink.Length;
qrCode.Text = portalLink;
// The size also sets TXBarcodeCore.Size
string svg = qrCode.GetSVG(new Size(5000, 5000));
File.WriteAllText("qrcode.svg", svg);
Before you set Text from user input, the static IsTextValid checks whether a text is valid for a barcode type, as Check Values Before Merging shows. GetDefaultText returns a valid sample text for a type, and the static GetMinimumTextLength and GetMaximumTextLength return the shortest and longest text it takes, for example to set UpperTextLength.
To keep a barcode's settings apart from a document, Save writes the barcode data to a file, a Stream, a TextWriter or an XmlWriter, and Load reads it into a TXBarcodeCore again. ViewChanged occurs when a change of the settings requires the barcode to be drawn again.
// Save the settings of the QR code and load them into a new object
qrCode.Save("qrcode-settings.xml");
TXBarcodeCore copy = new TXBarcodeCore();
copy.Create();
copy.Load("qrcode-settings.xml");
Charts
A chart in a document is a ChartFrame. The frame places the chart like a barcode, while the chart itself is a chart control of the type System.Windows.Forms.DataVisualization.Charting.Chart, which holds its appearance and data. Charts can only be used where the assembly with this class is available. This chart control of the .NET Framework wasn't ported to .NET; the blog article Using Charts with TX Text Control .NET for Windows 31.0 in .NET 6 describes a fork that makes it available in .NET 6 Windows Forms applications.
The chart controls offer more than 30 diagram types, such as bars, pies, donuts and financial series.
Insert a Chart
The following program needs a Windows project that references System.Windows.Forms.DataVisualization, from the .NET Framework or from the fork the blog article above describes. It binds a bar chart to the XML data below and inserts it at the input position:
<sales>
<points>
<country>Country 1</country>
<value>100</value>
</points>
<points>
<country>Country 2</country>
<value>120</value>
</points>
</sales>
Save the data as Documents/sales.xml. The program:
using System.Data;
using System.Windows.Forms.DataVisualization.Charting;
using TXTextControl;
using TXTextControl.DataVisualization;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Selection.Text = "Sales by country:\r\n";
// The chart control of the .NET Framework holds the appearance and the data
Chart chart = new Chart();
chart.ChartAreas.Add("chartArea1");
chart.Series.Add("series1");
chart.Series["series1"].ChartArea = "chartArea1";
chart.Series["series1"].ChartType = SeriesChartType.Bar;
DataSet data = new DataSet();
data.ReadXml("Documents/sales.xml");
chart.Series[0].XValueMember = data.Tables[0].Columns[0].ColumnName;
chart.Series[0].YValueMembers = data.Tables[0].Columns[1].ColumnName;
chart.DataSource = data.Tables[0];
chart.DataBind();
// The frame places the chart in the document
ChartFrame frame = new ChartFrame(chart)
{
Name = "sales"
};
// Inline at the input position
tx.Charts.Add(frame, -1);
tx.Save("sales.tx", StreamType.InternalUnicodeFormat);
}
The ChartFrame constructor takes the Chart control, which ChartFrame.Chart returns later. ChartCollection.Add has the same overloads as BarcodeCollection.Add: inline, anchored to a paragraph with an alignment or a location, and at a fixed position on a page or in the document.
What Else to Know About Charts
- Collections and events. ServerTextControl.Charts returns the ChartCollection of the main text, with
Add,GetItemandRemoveas for barcodes. ChartCreated occurs for each chart of a loaded document, and ChartDeleted when a chart is removed. After changing a chart, call ChartFrame.Refresh. - Formats. Charts are saved as charts in the TX Text Control format and RTF, and other formats contain an image of the chart. On a system without the chart controls, loading a document inserts the image of each chart.
- Charts in templates.
MailMergefills charts with data. The data relation of a chart, the tables and the columns for its axis labels and values, is stored in the template and set with Set Data Relation on the Chart Layout ribbon tab. Charts are merged only outside merge blocks, and ChartMerged occurs for each merged chart. The blog article Using MailMerge with Chart Objects and JSON Data connects a chart to JSON data this way.
The blog article Use Case: Blood Pressure Report with Charts in C# merges XML data into a template with two charts and a table of measurements. Its first two pages, exported to PDF, contain the charts as images:

Next Steps
- Barcodes: fill barcode placeholders with data in a mail merge.
- Text Frames and Shapes: place text and shapes in frames.
- Headers and Footers: add content that repeats on every page.
- Charts and Barcodes in the Document Editor: let users insert charts and barcodes.