Control Initialization and Document Access
When is the WPF TextControl ready for code that loads a document or inserts text? Not in the constructor of the window, where most WPF code starts, but once WPF has loaded the control into the window. Code that knows this moment, and the events that follow it, reads and changes the document reliably. The lifecycle of the control, the members that exist only at run time, and the patterns for opening a document at startup and reading it afterward are covered below.
The samples use a window with a TextControl named textControl1, as in Create Your First WPF Application, and the code goes into MainWindow.xaml.cs.
The Lifecycle of the Control
| Moment | What happens | What your code can do |
|---|---|---|
Constructor of the window, InitializeComponent | XAML creates the TextControl and sets the properties of its attributes, such as ViewMode and the names of its bars | Set properties of the control, attach event handlers, remember what to load later |
Loaded event of the TextControl | WPF has loaded the control into the window | Work with the document: load a file, insert text, set the focus |
| DocumentLoaded event | A new document has been loaded into the editor | Read the loaded document, such as its pages or fields |
| Changed event | Users or your code have changed the contents | Track unsaved changes |
| ContentsReset event | All text has been deleted, for example by ResetContents, and all attributes reset to the state after initialization | Reset state of your own that belongs to the old document |
Closing event of the window | The user closes the window; the document exists only in the control until your code saves it | Ask whether to save changes, and set Cancel to keep the window open |
The window creates and releases the TextControl; unlike a ServerTextControl, it needs no call to Create. Loaded belongs to WPF and occurs for every element; don't confuse it with DocumentLoaded, which TX Text Control raises for documents. Load and Save Documents in Getting Started shows a complete save-changes prompt for Closing.
Members That Exist Only at Run Time
The reference marks a number of members of the TextControl as "Runtime only". They describe the document, not the control, and can't be set in XAML. Among them are:
- The input position and selection: Selection,
InputPositionandInputFormat. - The document's collections:
Tables,Images,TextFrames,Barcodes,Drawings,TextFields,ApplicationFields,FormFields,HypertextLinks,Sections,HeadersAndFooters,ParagraphStyles,TrackedChangesandTextParts. - The state of the editor:
CanUndo,CanRedo,CanCopy,CanPaste,CanPrintandCanEdit.
Use these members from the Loaded handler on, or from event handlers that run later, such as the Click handler of a button. Used in the constructor, they fail or have no effect; Control Initialization in Troubleshooting describes the symptoms.
Open a Document When the Window Opens
A file passed on the command line, or by the window that opens this one, is known in the constructor, but can only be loaded when the control is ready. The following MainWindow.xaml connects the handlers:
<Window x:Class="MyWPFApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WPF="clr-namespace:TXTextControl.WPF;assembly=TXTextControl.WPF"
Title="MainWindow" Height="450" Width="800">
<DockPanel>
<WPF:StatusBar x:Name="statusBar1" DockPanel.Dock="Bottom" />
<WPF:TextControl x:Name="textControl1" StatusBar="statusBar1"
Loaded="textControl1_Loaded"
DocumentLoaded="textControl1_DocumentLoaded" />
</DockPanel>
</Window>
The code-behind remembers the file in the constructor and loads it in the Loaded handler:
using System;
using System.Windows;
using TXTextControl;
namespace MyWPFApp
{
public partial class MainWindow : Window
{
private readonly string startFile;
private bool initialized;
public MainWindow()
{
InitializeComponent();
// Only remember the file here: the editor isn't ready yet
string[] args = Environment.GetCommandLineArgs();
startFile = args.Length > 1 ? args[1] : null;
}
private void textControl1_Loaded(object sender, RoutedEventArgs e)
{
// Loaded can occur more than once, for example after the control was moved
if (initialized) return;
initialized = true;
if (startFile != null)
{
textControl1.Load(startFile, StreamType.WordprocessingML);
}
textControl1.Focus();
}
private void textControl1_DocumentLoaded(object sender, EventArgs e)
{
// The document is in the editor: read it now
Title = $"{textControl1.Pages} pages - MainWindow";
}
}
}
The code works as follows:
Environment.GetCommandLineArgsreturns the path of the program first, and then the arguments. The first argument is taken as the file to open, a DOCX file here.- Load replaces the document of the editor with the file.
StreamType.WordprocessingMLis the DOCX format. DocumentLoadedoccurs after the new document is in the editor. Pages is the number of its pages, which is known only now.Focusputs the keyboard focus into the editor, so the user can type at once.
Run Startup Code Once
WPF raises Loaded each time an element is loaded into the visual tree of a window. That happens more than once when the control is moved, for example into another panel, or when it sits in a tab of a TabControl, whose content WPF loads each time the tab is selected. Startup code that must not run twice, such as loading the first document, keeps a flag like initialized above. Code that should run every time, such as setting the focus, can stay outside the check.
Access the Document From Code
Once the control is loaded, code reaches the document through the members of the TextControl and the shared document classes of the namespace TXTextControl:
// Insert a heading at the input position
int start = textControl1.Selection.Start;
textControl1.Selection.Text = "Quarterly Report";
// Select the inserted text and make it bold
textControl1.Selection.Start = start;
textControl1.Selection.Length = "Quarterly Report".Length;
textControl1.Selection.Bold = true;
Selection is the selected text or the input position: setting its Text inserts text, and Start and Length select a range, whose formatting properties such as Bold then apply to it. Document Object Model describes the other classes.
Two rules keep document access working:
- Stay on the UI thread. The
TextControlbelongs to the user interface of the window. Work that runs on another thread, such as aTask, reaches it through theDispatcherof the window. Dispatcher and UI Thread Access explains how. - Process documents without the editor with
ServerTextControl. Documents that the user doesn't see, such as a batch conversion, are processed with a ServerTextControl instead of the editor. It isn't loaded into a window: call its Create method first. See Using ServerTextControl in Desktop Applications.
Next Steps
- Control Initialization: errors from code that runs too early.
- Embedding the Editor in Windows and UserControls: editors in user controls that load their documents when they are ready.
- Loading and Saving Documents: load and save documents in every format.
- Events: the events of the editor by subject.