# Performance Best Practices

> Every performance measure for Windows Forms apps with its measured effect, plus DefaultFormattingPrinter in Program.cs and a Stopwatch test of a merge.

- **Product:** TX Text Control .NET for Windows Forms
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET for Windows Forms > Performance > Performance Best Practices
- **2292 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/performance/best-practices/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/performance/best-practices/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/performance/best-practices/llms-full.txt

---

Most of what makes a Windows Forms application with TX Text Control feel fast comes down to a handful of decisions: which thread does the work, which class holds the document, in which format it is kept and how instances are created and disposed. The practices below collect those decisions in one place, each with the measurement behind it where Text Control has published one, and with the page that shows the code.

### At a Glance

| Practice | Effect | Read |
|---|---|---|
| Keep document work off the UI thread | The form responds while documents are converted or merged | [UI Threading and Background Operations](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/performance/threading/llms-full.txt) |
| Use `ServerTextControl` for work the user doesn't see | No undo history and no rendering for the screen | [Using ServerTextControl in Desktop Applications](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/servertextcontrol/llms-full.txt) |
| Dispose every `ServerTextControl` | `Create` keeps working; Windows allows 10,000 USER and 10,000 GDI handles per process | [Memory Usage and Resource Disposal](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/performance/memory-usage/llms-full.txt) |
| Build text with Selection objects | About twice as fast as inserting, selecting and formatting, in a server benchmark | [Large Documents](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/performance/large-documents/#build-large-content-in-one-step) |
| Switch the undo buffer off while code builds a document in the editor | Saves time and memory, according to the reference | [Switch the Buffer Off](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/editing-text/undo-redo/#switch-the-buffer-off) |
| Keep documents in the TX Text Control format until they're final | No conversion when loading and saving | [Document Loading and Conversion](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/performance/loading-conversion/llms-full.txt) |
| Use one `ServerTextControl` for a batch | 0.46 seconds for one large file, 0.18 seconds per file in a batch of 400 | [Document Loading and Conversion](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/performance/loading-conversion/#use-one-instance-for-a-batch) |
| Split long merge blocks | Two blocks merged faster than one block with the same rows | [Mail Merge Performance](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/performance/mail-merge/llms-full.txt) |
| Merge large batches in separate processes | 100 merges in 14 instead of 45 seconds on 16 cores | [Mail Merge Performance](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/performance/mail-merge/#merge-large-batches-in-separate-processes) |
| Compress images in PDF files | 14.68 MB down to 1.48 MB in a test document | [Large Documents](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/performance/large-documents/#keep-pdf-output-small) |
| Set a default formatting printer | No wait for a slow printer when a control is created | [Start Without Waiting for a Printer](#start-without-waiting-for-a-printer) |
| Measure your own workload | Every benchmark depends on its documents and hardware | [Measure Your Own Workload](#measure-your-own-workload) |

### Start Without Waiting for a Printer

TX Text Control formats text with the dimensions of a printer, so that the document on the screen matches the printed one. The printer named by [FormattingPrinter](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/formattingprinter-property/llms-full.txt) is contacted when a control is created, and a printer that responds slowly, such as a network printer in energy saving mode, delays the start. Even with `FormattingPrinter` set to `"Display"`, the default printer is contacted during initialization.

Since version 30.0, the static property `DefaultFormattingPrinter` sets the formatting device before any instance is created, and TX Text Control then doesn't contact any other printer or the print spooler. Set it at the start of *Program.cs*:

```csharp
using System;
using System.Windows.Forms;

internal static class Program
{
    [STAThread]
    static void Main()
    {
        ApplicationConfiguration.Initialize();

        // Before the first TextControl or ServerTextControl is created
        TXTextControl.TextControl.DefaultFormattingPrinter = "Display";
        TXTextControl.ServerTextControl.DefaultFormattingPrinter = "Display";

        Application.Run(new Form1());
    }
}
```

`"Display"` formats with the font dimensions of the screen, which look the same on every machine, instead of those of a particular printer. Keep a printer as formatting device if your documents must match that printer's output exactly. The blog article [Initialize Text Control Without a Printer (Completely)](https://www.textcontrol.com/blog/2022/02/28/initialize-text-control-without-a-printer-completely/) describes the property.

### Measure Your Own Workload

Text Control publishes no fixed numbers for desktop applications, and each benchmark above ran with its own documents and hardware, often the server product. Your templates, data, images and fonts decide how long your documents take. The following handler measures the four steps of a merge separately, creating the instance, loading the template, merging and saving, so that you know which one to improve. It uses the files of [Mail Merge Performance](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/performance/mail-merge/#merge-in-the-background-with-progress-and-cancel), *invoice.docx* and *invoice.json*:

```csharp
using System;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using TXTextControl;
using TXTextControl.DocumentServer;

private void measureButton_Click(object sender, EventArgs e)
{
    string json = File.ReadAllText("invoice.json");
    Stopwatch stopwatch = Stopwatch.StartNew();

    using (ServerTextControl tx = new ServerTextControl())
    {
        tx.Create();
        long create = stopwatch.ElapsedMilliseconds;

        stopwatch.Restart();
        tx.Load("invoice.docx", StreamType.WordprocessingML, new LoadSettings
        {
            ApplicationFieldFormat = ApplicationFieldFormat.MSWord,
            LoadSubTextParts = true
        });
        long load = stopwatch.ElapsedMilliseconds;

        stopwatch.Restart();
        using (MailMerge mailMerge = new MailMerge { TextComponent = tx })
        {
            mailMerge.MergeJsonData(json);
        }
        long merge = stopwatch.ElapsedMilliseconds;

        stopwatch.Restart();
        tx.Save("invoices.pdf", StreamType.AdobePDF);
        long save = stopwatch.ElapsedMilliseconds;

        MessageBox.Show(this, $"Create: {create} ms\nLoad: {load} ms\nMerge: {merge} ms\nSave: {save} ms");
    }
}
```

The code works as follows:

- `Stopwatch` from `System.Diagnostics` measures the elapsed time, and `Restart` starts each step at zero.
- The first run of a process includes one-time work. Text Control's benchmarks warm up before they measure or average several runs, so click the button several times and compare the later results.
- The measurement runs on the UI thread to keep the code short. Measure the same way inside `Task.Run` when you compare it with your background code.

Measure on computers like those of your users, with release builds and the documents they create.

### Next Steps

- [UI Threading and Background Operations](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/performance/threading/llms-full.txt) — the threading rules for `TextControl` and `ServerTextControl`.
- [Large Documents](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/performance/large-documents/llms-full.txt) — build and process long documents.
- [Mail Merge Performance](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/performance/mail-merge/llms-full.txt) — the measured costs of a merge.
- [Performance](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/performance/llms-full.txt) — the overview of this section.

---

## Nearby

- **Previous:** [Mail Merge Performance](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/performance/mail-merge/llms-full.txt)
- **Next:** [Troubleshooting](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/troubleshooting/llms-full.txt)
