Loading Documents
Contracts from a file share, templates from a database, PDF files from email: a Windows Forms application loads documents from many places and in many formats. One call of Load is enough for a file, but the details decide the result, from whether a document replaces, extends or goes into the current one to which fields and bookmarks are imported. Each of these choices is a button handler of its own, followed by the information LoadSettings returns about a loaded document and the errors a load can raise.
The Open dialog box and the load buttons of an editor are shown in Load and Save Documents and Loading and Saving Documents. Supported File Formats lists the StreamType value of each format. The examples work on the TextControl named textControl1 in Form1.cs, which needs using System.Windows.Forms; and using TXTextControl;. A ServerTextControl has the same methods.
Load, Append or Insert
Three methods load a document. They accept the same sources and formats and an optional LoadSettings object, and differ in what happens to the current contents:
| Method | What happens to the current contents |
|---|---|
| TextControl.Load | They're replaced completely |
| TextControl.Append | They stay; the document is added at the end, as an AppendSettings value sets |
| Selection.Load | The selected text is replaced; with nothing selected, the document is inserted at the input position |
The following handler loads a letter, appends a signature and inserts an attachment in place of a placeholder:
private void loadLetterButton_Click(object sender, EventArgs e)
{
// Load replaces the complete contents
textControl1.Load("letter.docx", StreamType.WordprocessingML);
// Append adds a document at the end, here in a new paragraph
textControl1.Append("signature.rtf", StreamType.RichTextFormat,
AppendSettings.StartWithNewParagraph);
// Selection.Load replaces the selected text, here a placeholder
const string placeholder = "[ATTACHMENT]";
int position = textControl1.Find(placeholder, 0, FindOptions.NoMessageBox);
if (position >= 0)
{
textControl1.Select(position, placeholder.Length);
LoadSettings loadSettings = new LoadSettings()
{
// Create a new paragraph before the document is loaded
AddParagraph = true
};
textControl1.Selection.Load("attachment.docx", StreamType.WordprocessingML, loadSettings);
}
}
The code works as follows:
- Find returns the zero-based position of the placeholder, or -1, and FindOptions
NoMessageBoxkeeps the editor from showing a message box about the result.Findsearches only the text part with the input focus, as Document Object Model explains. - LoadSettings.AddParagraph has an effect only with
Selection.Load. By default, the document is loaded into the existing paragraph, and the attributes of that paragraph and of the last loaded paragraph are merged. Withtrue, a new paragraph is created first and takes the attributes of the last loaded paragraph.
The last parameter of Append is a value of AppendSettings:
| Value | The appended document starts |
|---|---|
None | At the end of the last paragraph |
StartWithNewParagraph | In a new paragraph at the end of the document |
StartWithNewSection | In a new section at the end of the document |
Control the Import With LoadSettings
Properties of LoadSettings that you set before loading decide what is imported:
| Property | Sets | Default |
|---|---|---|
| ApplicationFieldFormat | Whether fields of Word and RTF documents are imported as application fields, as a value of ApplicationFieldFormat | None |
| ApplicationFieldTypeNames | The field types to import, such as MERGEFIELD, when ApplicationFieldFormat is MSWord | All types |
| LoadSubTextParts | Whether bookmarks that extend over several characters become subtext parts, for DOCX, DOC and RTF | false |
| LoadImages | Whether images are loaded; otherwise a rectangle with the image's name is shown | true |
| LoadHypertextLinks | Whether hypertext links are loaded | true |
| LoadDocumentBackColor | Whether the background color of the document is loaded | true |
| ImageSearchPath | A folder that replaces the absolute paths of linked images and other resources | — |
| DocumentBasePath | A base path that resolves the relative file paths of the document | — |
| PDFImportSettings | How the structure of a PDF document is rebuilt | GenerateTextFrames |
| DocumentPartName | The worksheet of an XLSX file; an empty string lets the user choose it in a dialog box | The first worksheet |
| UserPassword, MasterPassword | The passwords of an encrypted PDF document | — |
The following handler loads a Word template with its merge fields and merge blocks, and without its hypertext links and background color:
private void loadTemplateButton_Click(object sender, EventArgs e)
{
LoadSettings loadSettings = new LoadSettings()
{
ApplicationFieldFormat = ApplicationFieldFormat.MSWord,
ApplicationFieldTypeNames = new string[] { "MERGEFIELD" }, // only merge fields
LoadSubTextParts = true, // bookmarks over several characters become subtext parts
LoadHypertextLinks = false,
LoadDocumentBackColor = false
};
textControl1.Load("template.docx", StreamType.WordprocessingML, loadSettings);
MessageBox.Show($"Merge fields: {textControl1.ApplicationFields.Count}, " +
$"subtext parts: {textControl1.SubTextParts.Count}");
}
Without ApplicationFieldFormat, the fields of a Word document are not imported as fields, and ApplicationFields stays empty. The field formats of different applications aren't compatible, so the value names the one the document uses:
| Value | Imports |
|---|---|
None | No application fields; Word form fields become TX Text Control form fields |
MSWord | The fields of Microsoft Word, form fields included, as application fields |
MSWordTXFormFields | The fields of Microsoft Word as application fields, except form fields such as check boxes, drop-down lists and text form fields, which become TX Text Control form fields |
HighEdit | The fields of the Heiler HighEdit component as application fields |
The merge blocks of a mail merge template are subtext parts whose names begin with txmb_, so templates are loaded with LoadSubTextParts set to true to get them back in SubTextParts. Fields and Subtext Parts shows how to work with both, and PDF Import and Its Limitations the values of PDFImportSettings.
Read Information About a Loaded Document
After loading, the LoadSettings object you passed contains information about the document. This works with the dialog overloads too: Load with a StreamType and a LoadSettings object opens the Open dialog box, and afterward LoadedFile tells you which file the user chose:
private void openButton_Click(object sender, EventArgs e)
{
LoadSettings loadSettings = new LoadSettings();
// Opens the Open dialog box with the filters of these formats
DialogResult result = textControl1.Load(
StreamType.WordprocessingML | StreamType.RichTextFormat | StreamType.AdobePDF,
loadSettings);
if (result != DialogResult.OK)
{
return;
}
StringBuilder info = new StringBuilder();
info.AppendLine($"File: {loadSettings.LoadedFile}");
info.AppendLine($"Format: {loadSettings.LoadedStreamType}, {loadSettings.BytesRead} bytes");
info.AppendLine($"Title: {loadSettings.DocumentTitle}");
info.AppendLine($"Author: {loadSettings.Author}");
info.AppendLine($"Last modified: {loadSettings.LastModificationDate}");
if (loadSettings.UserDefinedDocumentProperties != null)
{
foreach (string name in loadSettings.UserDefinedDocumentProperties.Names)
{
info.AppendLine($"{name}: {loadSettings.UserDefinedDocumentProperties[name]}");
}
}
MessageBox.Show(info.ToString());
}
The handler needs using System.Text; as well. The properties that inform about the document are read only:
| Property | Contains |
|---|---|
LoadedFile, LoadedStreamType, BytesRead | The file with its path, the format that was loaded and the number of bytes read |
DocumentTitle, Author, DocumentSubject, DocumentKeywords, CreatorApplication | The metadata of the document |
CreationDate, LastModificationDate | The dates of the document; January 1, 0001 if the document has none |
| UserDefinedDocumentProperties | A UserDefinedPropertyDictionary with the user-defined properties, or null |
| PageSize, PageMargins | The page size, 0 if the document has none, and the page margins, -1 if the document has none |
| DocumentAccessPermissions | What may be done with a loaded PDF document |
The Names of the dictionary are the property names, and its values are strings, Boolean values, integers or double values. TextControl.DocumentSettings receives the same metadata and keeps it for the next save.
Load From Byte Arrays, Strings and Streams
Documents from a database arrive as bytes, and HTML or RTF often as a string. The overloads take a BinaryStreamType for a byte array and a StringStreamType for a string:
private void loadFromDatabaseButton_Click(object sender, EventArgs e)
{
// For example the contents of a database column
byte[] data = File.ReadAllBytes("invoice.docx");
textControl1.Load(data, BinaryStreamType.WordprocessingML);
// HTML and RTF are loaded from a string
string html = "<h1>Terms</h1><p>Payment is due within 14 days.</p>";
textControl1.Append(html, StringStreamType.HTMLFormat, AppendSettings.StartWithNewSection);
}
BinaryStreamType has values for DOCX, DOC, PDF, XLSX and the TX Text Control formats, but not for HTML and RTF, which are loaded from a string or a file. The stream overload of Load takes a FileStream. For any other stream, such as a MemoryStream, read its bytes with ToArray() and load the byte array. The handler needs using System.IO;.
Load Password-Protected PDF Documents
A PDF document protected with a user password opens only with that password. Without it, Load throws a FilterException whose Reason is InvalidPassword; loaded again with the password in LoadSettings.UserPassword, it opens, and DocumentAccessPermissions tells what it allows. Open a Password-Protected PDF asks the user for the password and applies the permissions in the editor.
Handle Errors
When a document can't be imported, Load throws a FilterException whose Reason names the cause, such as WrongFileType or InvalidPassword. Handle Errors When Loading and Saving turns the reasons into messages for the user, and Document Conversion in Troubleshooting explains each reason and its fix. AdobePDFA and CascadingStylesheet are formats for saving only. After a successful load, the DocumentLoaded event of the TextControl occurs, a good place to update the title bar or the state of your buttons.
Next Steps
- Saving and Converting Documents: save loaded documents in another format.
- Creating Documents: assemble documents from several sources.
- Fields and Subtext Parts: work with the fields imported from Word documents.
- Document Loading and Conversion: load large numbers of documents efficiently.