# Dispatcher and UI Thread Access

> Which TX Text Control objects belong to the WPF UI thread, how documents cross threads as byte arrays, and CheckAccess and InvokeAsync for the TextControl.

- **Product:** TX Text Control .NET for WPF
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET for WPF > Performance > Dispatcher and UI Thread Access
- **2173 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/dispatcher/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/dispatcher/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/dispatcher/llms-full.txt

---

In WPF, every control belongs to the thread that created it, and the WPF `TextControl` is a control like any other: the UI thread of its window owns it, and the `Dispatcher` of that thread is the only way in from anywhere else. Knowing this model tells you which TX Text Control objects your background code may touch, how a document crosses from one thread to another, and how a result gets back into the editor.

### How WPF Assigns Controls to Threads

[TextControl](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/llms-full.txt) in the `TXTextControl.WPF` namespace derives from `System.Windows.Controls.Control`. Like every WPF element, it is bound to the thread that created it, the UI thread of the window, and WPF throws an `InvalidOperationException` when another thread calls it. The `Dispatcher` of that thread runs the window's work one item at a time: input, layout, rendering and your event handlers. As long as one of your handlers runs, nothing else in the window happens.

| Object | May be used on | Reason |
|---|---|---|
| The WPF `TextControl`, `ButtonBar`, `RulerBar`, `StatusBar` and ribbon | The UI thread of their window | WPF controls, bound to the thread that created them |
| [ServerTextControl](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/servertextcontrol/llms-full.txt) | Any thread, one instance per thread | A `System.ComponentModel.Component` without a user interface, meant for work in the background |
| [MailMerge](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver/mailmerge/llms-full.txt) | The thread of the text component it works on | It merges into the document of its `TextComponent` |
| Byte arrays with documents | Any thread | Plain data, which your code passes between threads |

`Load`, `Save` and the merge methods of `MailMerge` are synchronous. Called in a handler, they occupy the dispatcher until they return, and the window freezes for that time. [Background Operations](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/background-operations/llms-full.txt) moves such work to other threads.

### Hand a Document to Another Thread

The document of the editor can't leave the UI thread, but a copy of it can. The following handler in *MainWindow.xaml.cs* copies the editor's document into a byte array, creates a PDF file from it in a `ServerTextControl` on a thread of the thread pool and returns to the window afterward. It needs a button named `exportPdfButton` in *MainWindow.xaml*:

```csharp
using System;
using System.Threading.Tasks;
using System.Windows;
using TXTextControl;

private async void ExportPdf_Click(object sender, RoutedEventArgs e)
{
    // On the UI thread: copy the editor's document
    textControl1.Save(out byte[] document, BinaryStreamType.InternalUnicodeFormat);

    exportPdfButton.IsEnabled = false;

    try
    {
        await Task.Run(() =>
        {
            // On a thread of the thread pool: no WPF element in here
            using (ServerTextControl tx = new ServerTextControl())
            {
                if (!tx.Create())
                {
                    throw new InvalidOperationException("TX Text Control could not be initialized.");
                }

                tx.Load(document, BinaryStreamType.InternalUnicodeFormat);
                tx.Save("document.pdf", StreamType.AdobePDF);
            }
        });

        MessageBox.Show(this, "document.pdf created.");
    }
    finally
    {
        // Back on the UI thread after await
        exportPdfButton.IsEnabled = true;
    }
}
```

The code works as follows:

- [WPF.TextControl.Save](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/save-method/llms-full.txt) with [BinaryStreamType](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/binarystreamtype/enumeration/llms-full.txt) `InternalUnicodeFormat` copies the complete document, in the TX Text Control format, into a byte array. The user can keep editing while the copy is exported.
- The lambda of `Task.Run` uses only the byte array and a `ServerTextControl` it creates itself. [Create](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/servertextcontrol/create-method/llms-full.txt) returns `false` if the instance couldn't be initialized.
- `await` in an event handler of the window continues on the UI thread, so the message box and the button are used on the thread that owns them. An exception of the task is thrown again there; [Catch Errors of Background Work](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-processing/exceptions/#catch-errors-of-background-work) shows how to handle it.

### Get Back to the UI Thread With the Dispatcher

Code that runs on another thread and isn't awaited from a handler, such as a callback of another component or a timer of `System.Threading`, reaches the editor through its `Dispatcher`. `CheckAccess` tells whether the current thread owns the control, and `InvokeAsync` queues a call on the owning thread:

```csharp
using System;
using System.Windows;
using TXTextControl;

private void ShowDocument(byte[] document)
{
    // Called on another thread: queue the call on the UI thread
    if (!textControl1.Dispatcher.CheckAccess())
    {
        textControl1.Dispatcher.InvokeAsync(() => ShowDocument(document));
        return;
    }

    textControl1.Load(document, BinaryStreamType.InternalUnicodeFormat);
}
```

The code works as follows:

- `Dispatcher`, `CheckAccess` and `InvokeAsync` are members that every WPF control inherits. `InvokeAsync` returns at once, so the background thread doesn't wait for the window.
- [WPF.TextControl.Load](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/load-method/llms-full.txt) replaces the document of the editor and runs on the UI thread.

For reports that arrive regularly, such as the progress of a long task, `Progress<T>` does the same with less code: created on the UI thread, it calls its handler there for each report, as [Background Operations](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/background-operations/#convert-many-files-with-progress-and-cancel) shows.

### Keep the Dispatcher Free

- **Don't wait on the UI thread.** A handler that calls `Wait()` or reads `Result` of a task blocks the dispatcher just as `Load` does, and when the task itself needs the UI thread, neither can go on. Use `await` instead.
- **Split work that must stay in the editor.** Some work needs the `TextControl` itself, such as building a document the user watches. Build larger parts in a `ServerTextControl` and insert them in one step, as [Large Documents](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/large-documents/#build-large-content-in-one-step) shows.
- **Start after Loaded.** The control works with documents once WPF has loaded it into the window, so startup code belongs in its `Loaded` event, as [Control Initialization](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/troubleshooting/initialization/llms-full.txt) explains.
- **Catch what nobody catches.** An exception on the UI thread that no handler catches ends the application. The TX Words samples handle `Application.Current.DispatcherUnhandledException`, as [Dispatcher and Thread Access](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/troubleshooting/dispatcher/#an-exception-ends-the-application) in Troubleshooting describes.

### Next Steps

- [Background Operations](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/background-operations/llms-full.txt) — convert and merge on other threads with progress and cancellation.
- [Using ServerTextControl in Desktop Applications](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-processing/servertextcontrol/llms-full.txt) — the lifecycle of `ServerTextControl`.
- [Architecture and Control Lifecycle](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/architecture/llms-full.txt) — where code belongs in the life of the control.
- [Memory Usage and Resource Disposal](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/memory-usage/llms-full.txt) — dispose every instance a thread creates.

---

## Nearby

- **Previous:** [Performance](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/llms-full.txt)
- **Next:** [Background Operations](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/background-operations/llms-full.txt)
