Exceptions and Error Handling
Which calls of TX Text Control can fail, and how does a WPF application find out? Errors of the document engine, such as a file that can't be converted or a feature outside the licensed edition, arrive as exceptions of TX Text Control. Wrong arguments cause the usual .NET exceptions, and many expected failures come back as a return value instead. Each needs its own handling in the code-behind: a try block, a check of the result, or a handler of last resort for the whole application.
The examples belong in MainWindow.xaml.cs with the TextControl named textControl1. Specific error messages and their fixes are collected in Troubleshooting.
MainWindow.xaml.cs needs these using directives:
using System;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.Win32;
using TXTextControl;
How TX Text Control Reports Errors
| Kind of error | How it's reported | Examples |
|---|---|---|
| An error of the document engine | An exception class of TX Text Control | A document that can't be loaded |
| Wrong use of the programming interface | ArgumentException, ArgumentNullException or ArgumentOutOfRangeException for a wrong parameter or property value; InvalidOperationException for a call that the object's state doesn't allow | A conditional instruction without a name |
| An expected failure | A return value | An Add method returns false or an AddResult; ServerTextControl.Create returns false |
Return values throw nothing, so check them where your code depends on the result.
TX Text Control Exceptions
- FilterException: a document can't be converted to or from a format while it is loaded or saved.
- LicenseLevelException: the licensed edition doesn't contain the feature your code uses.
- TextEditorException: an error occurs while text is edited.
- FormulaException and NumberFormatException: a table formula or the number format of its result has invalid syntax. FormulaException.CharacterIndex and NumberFormatException.CharacterIndex point at the first invalid character, counting from 1.
- DocumentServer.MergeCanceledException: a merge was canceled with DataRowMergedEventArgs.Cancel.
- DocumentServer.Json.ParserException and the classes derived from it: MailMerge.MergeJsonData received invalid JSON.
Each message contains an error number in parentheses, for example (1-1D01). It is more exact than the text of the message; the blog article Text Control Error Navigator Launched explains how to look it up.
Catch Errors When Opening a Document
Documents come from outside your application, so loading needs a try block. FilterException.Reason is a FilterException.FilterError value that names the cause:
private void Open_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog { Filter = "Word documents|*.docx" };
if (dialog.ShowDialog(this) != true)
{
return;
}
try
{
textControl1.Load(dialog.FileName, StreamType.WordprocessingML);
}
catch (FilterException exception)
{
string text = exception.Reason switch
{
FilterException.FilterError.WrongFileType => "The file isn't a Word document.",
FilterException.FilterError.Encrypted => "The document is encrypted.",
FilterException.FilterError.CannotOpen => "The file couldn't be opened.",
_ => "The document couldn't be loaded."
};
MessageBox.Show(this, $"{text}\n\n{exception.Message}", "Open", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
The code works as follows:
OpenFileDialogofMicrosoft.Win32is the file dialog of WPF; itsShowDialogreturns a nullablebool.- WPF.TextControl.Load throws the
FilterExceptionwhen the document can't be converted. - The
switchexpression gives three common reasons a message of their own. Others areCannotRead,FileTooBig,Unsupported,NotWellFormedandInvalidPassword, and saving can fail withNonEmbeddableFont, for example. - Errors of the file system, such as an
IOExceptionfor a locked file, aren't aFilterException; catch them separately if needed.
Every reason and its fix is listed in Document Conversion in Troubleshooting.
Handle a Feature of Another Edition
A LicenseLevelException points to code that uses a feature the licensed edition doesn't have, such as form fields in the Professional edition. Change the code or the license: Editions lists the features per edition, and Licensing in Troubleshooting shows the messages. Where the application can go on without the feature, catch the exception:
private void InsertFormField_Click(object sender, RoutedEventArgs e)
{
try
{
textControl1.FormFields.Add(new TextFormField(1440));
}
catch (LicenseLevelException exception)
{
MessageBox.Show(this, exception.Message, "Not available", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
Catch Errors of Background Work
Code in Task.Run runs on another thread, and an exception there is stored in the task. await throws it again on the UI thread, so a try block around the await catches it:
private async void Convert_Click(object sender, RoutedEventArgs e)
{
try
{
await Task.Run(() =>
{
using (ServerTextControl tx = new ServerTextControl())
{
if (!tx.Create())
{
throw new InvalidOperationException("TX Text Control could not be initialized.");
}
tx.Load("contract.docx", StreamType.WordprocessingML);
tx.Save("contract.pdf", StreamType.AdobePDF);
}
});
MessageBox.Show(this, "contract.pdf created.");
}
catch (FilterException exception)
{
MessageBox.Show(this, $"{exception.Reason}: {exception.Message}", "Conversion failed");
}
}
The using block disposes the ServerTextControl even when an exception leaves it. Using ServerTextControl in Desktop Applications covers background work. A MergeCanceledException from a merge you cancel in a DataRowMerged handler is caught the same way around the call that merges; Merge Events describes the event.
Handle Exceptions Nobody Caught
An exception that reaches the WPF dispatcher without a catch block ends the application. The TX Words samples handle the DispatcherUnhandledException event of the application, show the message and mark the exception as handled, so that the user can continue after a LicenseLevelException. Attach the handler in App.xaml.cs:
using System.Windows;
using System.Windows.Threading;
public partial class App : Application
{
public App()
{
DispatcherUnhandledException += App_DispatcherUnhandledException;
}
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
MessageBox.Show(e.Exception.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
// Continue only after exceptions the application can recover from
e.Handled = e.Exception is TXTextControl.LicenseLevelException;
}
}
e.Handled = true keeps the application running. Set it only for exceptions after which your application is in a usable state, and catch other errors where you call TX Text Control. Dispatcher and Thread Access in Troubleshooting describes the case.
Next Steps
- Troubleshooting: error messages and their fixes.
- Document Conversion: every
FilterExceptionreason. - Loading Documents: load settings for protected and special documents.
- Handling Untrusted Documents: documents from unknown sources.