TX Text Control .NET for WPF

Text and Paragraph Formatting

Topic

Fonts, sizes, colors, alignment, indents and tab stops are what users change most often in a document, and the WPF TextControl lets them do it with the ribbon, the mini toolbar and built-in dialog boxes. For your code, the same attributes are properties of Selection and ParagraphFormat. The sections below show both sides, point out where WPF types get in the way, and keep your own buttons in step with the text. Named styles are covered in Stylesheets, and lists in Bullets and Numbered Lists.

How Formatting Works

TX Text Control distinguishes character formatting, such as font, size, bold and color, from paragraph formatting, such as alignment, indents, spacing and tab stops. Your code sets both through Selection, the selection in the text part that has the input focus:

  • With text selected, character attributes change the selected characters, and paragraph attributes change all paragraphs the selection touches.
  • Without a selection, character attributes apply at the input position, to the text typed next, and paragraph attributes to the current paragraph.

Sizes and distances are given in twips: 20 twips are 1 point, 1,440 twips 1 inch, and about 567 twips 1 centimeter. The FontFamily, FontSize, FontStyle and FontWeight dependency properties of the WPF TextControl itself follow WPF conventions instead: its FontSize, for example, is measured in device-independent units of 1/96 inch. Formatting the text of the document goes through Selection.

For users, the WPF RibbonFormattingTab, connected by name through RibbonFormattingTab of the TextControl, offers the character and paragraph attributes. The text mini toolbar, turned on with ShowMiniToolbar, offers the common ones right next to the selected text:

The WPF text mini toolbar with font name, font size, bold, italic, underline, text color, list, alignment and styles buttons above a table.

Toolbars and Mini Toolbars and Connecting Ribbon Tabs in XAML describe both.

Format Characters

Two buttons in MainWindow.xaml, <Button Content="Bold" Click="boldButton_Click" /> and <Button Content="Heading" Click="headingButton_Click" />, call these handlers in MainWindow.xaml.cs:

private void boldButton_Click(object sender, RoutedEventArgs e)
{
    // Toggle bold for the selected text or the input position
    textControl1.Selection.Bold = !textControl1.Selection.Bold;
}

private void headingButton_Click(object sender, RoutedEventArgs e)
{
    textControl1.Selection.FontName = "Arial";
    textControl1.Selection.FontSize = 320;   // 16 points, in twips
    textControl1.Selection.ForeColor = System.Drawing.Color.DarkBlue;
    textControl1.Selection.Underline = FontUnderlineStyle.Single;
}

The colors are System.Drawing.Color values, not the System.Windows.Media.Color of WPF, so the sample writes them in full; the file needs using TXTextControl;.

A Selection has these character attributes:

PropertySets
Bold, Italic, StrikeoutFont styles, true or false
UnderlineNone, Single, Doubled, SingleWordsOnly or DoubledWordsOnly
FontNameThe font
FontSizeThe size in twips, by default 200 twips (10 points)
ForeColor, TextBackColorText color and text background color
BaselineRaises (positive) or lowers (negative) the text, in twips
AutoBaselineAutomatic superscript or subscript with a scaled font
CapitalsCapitals, small capitals or petite capitals for lowercase letters
CharacterSpacing, CharacterScalingAdditional space per character in twips, and character width in percent

AutoBaseline, Capitals, CharacterSpacing and CharacterScaling were added in version 30.0.

Format a Range Your Code Inserted

A new Selection with a start position and a length selects and formats a range in one step when you assign it. In the Loaded handler of the control:

private void textControl1_Loaded(object sender, RoutedEventArgs e)
{
    textControl1.Text = "Quarterly Report";

    // Select characters 0 to 9 ("Quarterly") and format them
    Selection selection = new Selection(0, 9);
    selection.Bold = true;
    selection.Italic = true;
    textControl1.Selection = selection;
}

Text replaces the document with plain text. Selections and Caret Position explains selections in detail.

Format Paragraphs

Selection.ParagraphFormat takes a ParagraphFormat object with the paragraph attributes to set:

private void paragraphButton_Click(object sender, RoutedEventArgs e)
{
    ParagraphFormat format = new ParagraphFormat();
    format.Alignment = TXTextControl.HorizontalAlignment.Justify;
    format.LeftIndent = 567;       // 1 cm, in twips
    format.TopDistance = 120;      // 6 points before the paragraph
    format.BottomDistance = 120;   // 6 points after the paragraph
    format.LineSpacing = 150;      // 150 percent
    format.Frame = TXTextControl.Frame.BottomLine;
    format.FrameLineWidth = 20;
    format.FrameStyle = FrameStyle.Single;

    textControl1.Selection.ParagraphFormat = format;
}

Write TXTextControl.HorizontalAlignment in full. In a file with using System.Windows;, a plain HorizontalAlignment is ambiguous with the WPF enumeration of the same name, and the code doesn't compile. Write TXTextControl.Frame in full, too: with using System.Windows.Controls;, a plain Frame is ambiguous with the WPF Frame control.

PropertySets
AlignmentLeft, Right, Center or Justify
LeftIndent, RightIndentIndents in twips
HangingIndentA hanging indent in twips; negative values indent the first line
TopDistance, BottomDistanceSpace before and after the paragraph in twips
LineSpacing, AbsoluteLineSpacingLine spacing as a percentage of the font size, or in twips
Frame, FrameStyle, FrameLineWidthFrame lines: LeftLine, RightLine, TopLine, BottomLine, Box or MergedBox, single or double
BackColorThe paragraph background
KeepLinesTogether, KeepWithNext, PageBreakBefore, WidowOrphanLinesPage break rules
DirectionLeft-to-right or right-to-left
StructureLevelLevel 0 to 10 for tables of contents; 0 is body text

Tables of Contents uses the structure levels, and Right-to-Left UI covers the writing direction.

Set Tab Stops

TabPositions, TabTypes and TabLeaders are parallel arrays, one entry per tab stop, with positions in twips. MaxTabs limits a paragraph to 14 tabs.

private void tabsButton_Click(object sender, RoutedEventArgs e)
{
    ParagraphFormat format = new ParagraphFormat();
    format.TabPositions = new int[] { 2835, 5670 };                 // 5 cm and 10 cm
    format.TabTypes = new TabType[] { TabType.LeftTab, TabType.DecimalTab };
    format.TabLeaders = new TabLeader[] { TabLeader.None, TabLeader.Dot };

    textControl1.Selection.ParagraphFormat = format;
    textControl1.Selection.Text = "Item\t\t12.50";
}

TabType values are LeftTab, RightTab, CenterTab, DecimalTab, which aligns the decimal sign, and RightBorderTab. TabLeader fills the gap with Period, Dot, Dash or Underline, or not at all with None.

Users set the same values in the Tabs dialog box, which TabDialog opens: a list of the tab stop positions of the paragraph, the alignment and the leader of the selected tab stop, and Set, Clear and Clear All buttons:

The Tabs dialog box with the tab stop position list, the Leader list open with None and three leader styles, the Right most tab option and the Set, Clear and Clear All buttons.

Use the One-Click Commands

These Selection methods do what the corresponding ribbon buttons do, for the selection or at the input position:

  • GrowFont and ShrinkFont change the font size in the steps that the button bar and the font dialog box offer.
  • IncreaseIndent and DecreaseIndent change the left indent, to positions taken from the tab positions and the indents of the surrounding paragraphs.
  • RemoveFormatting resets the character attributes to their defaults, and also the paragraph attributes when nothing or more than one paragraph is selected.

Open the Built-In Dialog Boxes

Each formatting dialog box is one method call: FontDialog, ParagraphFormatDialog, TabDialog, ForeColorDialog, TextBackColorDialog and LanguageDialog. A Paragraph... menu item, <MenuItem Header="Paragraph..." Click="MenuItemParagraph_Click" />, calls textControl1.ParagraphFormatDialog(); in its handler. Built-in Dialog Boxes lists every dialog box of the editor with its return values and the indexes of its tabs.

Keep Your Own Controls in Step

Your own formatting buttons have to reflect the text at the input position. CharFormatChanged occurs when the character attributes of the selection or the input position change, and ParagraphFormatChanged when the paragraph attributes do. Connect the handler in XAML with CharFormatChanged="textControl1_CharFormatChanged" or in the constructor of the window:

private void textControl1_CharFormatChanged(object sender, EventArgs e)
{
    // Show the font of the selection in the title bar
    if (textControl1.Selection.IsCommonValueSelected(Selection.Attribute.FontName))
    {
        Title = textControl1.Selection.FontName + ", " + (textControl1.Selection.FontSize / 20) + " pt";
    }
    else
    {
        Title = "Several fonts";
    }
}

If the selection mixes values, a Selection property returns its default value. IsCommonValueSelected with a Selection.Attribute value says whether the whole selection shares one. InputFormat returns an InputFormat object with all attributes at the input position as nullable values, such as bool? for Bold.

Next Steps