TX Text Control .NET for Windows Forms

Loading Documents

Topic

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:

MethodWhat happens to the current contents
TextControl.LoadThey're replaced completely
TextControl.AppendThey stay; the document is added at the end, as an AppendSettings value sets
Selection.LoadThe 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 NoMessageBox keeps the editor from showing a message box about the result. Find searches 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. With true, 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:

ValueThe appended document starts
NoneAt the end of the last paragraph
StartWithNewParagraphIn a new paragraph at the end of the document
StartWithNewSectionIn 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:

PropertySetsDefault
ApplicationFieldFormatWhether fields of Word and RTF documents are imported as application fields, as a value of ApplicationFieldFormatNone
ApplicationFieldTypeNamesThe field types to import, such as MERGEFIELD, when ApplicationFieldFormat is MSWordAll types
LoadSubTextPartsWhether bookmarks that extend over several characters become subtext parts, for DOCX, DOC and RTFfalse
LoadImagesWhether images are loaded; otherwise a rectangle with the image's name is showntrue
LoadHypertextLinksWhether hypertext links are loadedtrue
LoadDocumentBackColorWhether the background color of the document is loadedtrue
ImageSearchPathA folder that replaces the absolute paths of linked images and other resources—
DocumentBasePathA base path that resolves the relative file paths of the document—
PDFImportSettingsHow the structure of a PDF document is rebuiltGenerateTextFrames
DocumentPartNameThe worksheet of an XLSX file; an empty string lets the user choose it in a dialog boxThe first worksheet
UserPassword, MasterPasswordThe 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:

ValueImports
NoneNo application fields; Word form fields become TX Text Control form fields
MSWordThe fields of Microsoft Word, form fields included, as application fields
MSWordTXFormFieldsThe 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
HighEditThe 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:

PropertyContains
LoadedFile, LoadedStreamType, BytesReadThe file with its path, the format that was loaded and the number of bytes read
DocumentTitle, Author, DocumentSubject, DocumentKeywords, CreatorApplicationThe metadata of the document
CreationDate, LastModificationDateThe dates of the document; January 1, 0001 if the document has none
UserDefinedDocumentPropertiesA UserDefinedPropertyDictionary with the user-defined properties, or null
PageSize, PageMarginsThe page size, 0 if the document has none, and the page margins, -1 if the document has none
DocumentAccessPermissionsWhat 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