Footnotes
A footnote places a comment or a source at the bottom of the page without breaking the flow of the text. The WPF TextControl supports footnotes in the user interface, through the References tab of the ribbon, and in code, through its Footnotes collection: insert them, number them, go from one to the next and react when the user works with them.
The examples use a window with a TextControl named textControl1, as in Create Your First WPF Application. Footnotes were introduced in version 32.0 and are part of the Enterprise edition; see Editions and Feature Availability.
Reference Marks and Footnotes
Every footnote consists of two parts:
- The reference mark, a number at the position in the text that the footnote refers to.
- The footnote at the bottom of the page. It begins with a footnote mark, which repeats the number, followed by the footnote text.
All footnotes of a document share one number format and one start number, and they are numbered from the beginning to the end of the document. A footnote inserted in front of others gets the lower number, and the following footnotes are renumbered. The footnote text can be formatted like any other text and can contain tables and images.
Only the main text can hold footnotes; headers, footers and text frames can't. Footnotes are saved in the TX Text Control format (.tx), in RTF and in the Word formats DOC and DOCX.
WPF.TextControl.Footnotes returns a FootnoteCollection with one Footnote object per footnote. These classes are the same in the Windows Forms and WPF products; the footnote events are members of the WPF TextControl:

Connect the References Tab
WPF.RibbonReferencesTab is a ribbon tab with a Footnotes group. Its buttons insert a footnote, delete and edit the current one, go to the previous or next footnote and highlight the marks, and two more items set the start number and the number format.
The tab goes into a Ribbon in MainWindow.xaml. The TextControl finds it through its name, which you assign to the RibbonReferencesTab property. The following window also has a row of buttons for the code in the next sections:
<Window x:Class="SampleApp.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="600" Width="900">
<DockPanel>
<Ribbon DockPanel.Dock="Top">
<WPF:RibbonReferencesTab x:Name="ribbonReferencesTab" />
</Ribbon>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<Button Content="Insert Footnote" Click="InsertFootnote_Click" />
<Button Content="List Footnotes" Click="ListFootnotes_Click" />
<Button Content="Next Footnote" Click="NextFootnote_Click" />
<Button Content="Remove Footnote" Click="RemoveFootnote_Click" />
</StackPanel>
<WPF:TextControl x:Name="textControl1"
RibbonReferencesTab="ribbonReferencesTab"
Loaded="textControl1_Loaded"
FootnoteReferenceMarkEntered="textControl1_FootnoteReferenceMarkEntered" />
</DockPanel>
</Window>
Replace SampleApp with the namespace of your project. Built-in Ribbon Tabs and Connecting Ribbon Tabs in XAML describe the ribbon tabs and how they are connected.
Set the Number Format When the Control Is Loaded
The numbering belongs to the collection. Set it in MainWindow.xaml.cs, in the handler of the Loaded event of the TextControl that the XAML above connects:
using System.Text;
using System.Windows;
using TXTextControl;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void textControl1_Loaded(object sender, RoutedEventArgs e)
{
// Number all footnotes i, ii, iii and highlight their marks
textControl1.Footnotes.NumberFormat = NumberFormat.SmallRomanNumbers;
textControl1.Footnotes.StartNumber = 1;
textControl1.Footnotes.HighlightMode = HighlightMode.Always;
textControl1.Focus();
}
}
Keep the namespace that Visual Studio created around the class. Add the handlers of the following sections to the same class.
- NumberFormat is a value of NumberFormat:
ArabicNumbers,Letters,CapitalLetters,RomanNumbersorSmallRomanNumbers. - StartNumber is the number of the first footnote.
- HighlightMode highlights the reference and footnote marks of all footnotes:
Always,Never(the default) orActivated, which highlights the marks that contain the input position. Footnote.HighlightMode and Footnote.HighlightColor change it for a single footnote.HighlightColoris aSystem.Drawing.Color, not a WPF color.
Insert a Footnote
The Insert Footnote button inserts a footnote at the input position:
private void InsertFootnote_Click(object sender, RoutedEventArgs e)
{
// The footnote text, a name and an ID; 0 means no ID
Footnote footnote = new Footnote("Source: annual report 2025, page 12.", "source", 0);
// true: move the input position into the footnote text
if (!textControl1.Footnotes.Add(footnote, true))
{
MessageBox.Show(this, "A footnote can't be inserted at this position.");
}
// Give the keyboard focus back to the editor
textControl1.Focus();
}
- The Footnote constructor takes the footnote text and, optionally, a name and an ID that identify the footnote in your code. An empty name and an ID of 0 mean none.
- FootnoteCollection.Add inserts the reference mark and the footnote. With
true, the input position moves into the footnote text so that the user can continue typing there. It returnsfalsewhere no footnote can be inserted. Focusgives the keyboard focus back to theTextControlafter the click on the button, so that the user can type the footnote text.
To edit the text of an existing footnote, call Footnote.Edit: it sets the input position at the end of the footnote text, where it can be changed and formatted like other text.
List, Find and Remove Footnotes
private void ListFootnotes_Click(object sender, RoutedEventArgs e)
{
StringBuilder list = new StringBuilder();
foreach (Footnote footnote in textControl1.Footnotes)
{
// Text begins with the footnote mark
list.AppendLine(footnote.Number + " (" + footnote.Name + "): " + footnote.Text);
}
MessageBox.Show(this, list.ToString(), textControl1.Footnotes.Count + " footnotes");
}
private void NextFootnote_Click(object sender, RoutedEventArgs e)
{
// true: the next footnote after the input position, false: the previous one
Footnote footnote = textControl1.Footnotes.GetItem(true);
footnote?.ScrollTo();
}
private void RemoveFootnote_Click(object sender, RoutedEventArgs e)
{
Footnote footnote = textControl1.Footnotes.GetItem("source");
if (footnote != null)
{
textControl1.Footnotes.Remove(footnote);
}
}
The code works as follows:
- Number is the number of the footnote in the text flow, starting with 1; the indexer
textControl1.Footnotes[1]returns a footnote by this number. Text is the plain footnote text with the footnote mark in front of it. Footnote.Save returns it in a format such as RTF or HTML. - GetItem returns the footnote at the input position, the next (
true) or previous (false) one, or the one with an ID or a name, andnullwhen there is none. - ScrollTo sets the input position at the footnote mark and scrolls it into view.
- Remove deletes the footnote with its reference mark and renumbers the following ones.
Name, ID and Reference Mark of a Footnote
The name and the ID given to the constructor stay available as properties of the footnote, which your code can read and change later. Name is a string, empty for a footnote without a name, and ID a number of your choice starting at 1, where 0 means none. Two read-only properties locate the reference mark in the text: ReferenceMarkStart is the one-based index of its first character and ReferenceMarkLength the number of its characters.
The following handlers select the reference mark of the footnote named "source", and move to the footnote at the input position with its footnote mark at the top of the visible part:
private void SelectReferenceMark_Click(object sender, RoutedEventArgs e)
{
Footnote footnote = textControl1.Footnotes.GetItem("source");
if (footnote != null)
{
// ReferenceMarkStart is one-based, Select expects a zero-based position
textControl1.Select(footnote.ReferenceMarkStart - 1, footnote.ReferenceMarkLength);
}
}
private void ShowFootnote_Click(object sender, RoutedEventArgs e)
{
// The footnote at the input position, or null
Footnote footnote = textControl1.Footnotes.GetItem();
// Move to the footnote mark and scroll it to the top
footnote?.ScrollTo(InputPosition.ScrollPosition.Top);
}
WPF.TextControl.Select sets the start and length of the selection. ScrollTo() without a parameter chooses the scroll position itself and returns true if the document was scrolled; the overload with an InputPosition.ScrollPosition value (Left, Top, Right or Bottom) places the footnote mark at that side of the visible part. Both overloads move the input position to the footnote mark.
The static Footnote.DefaultHighlightColor returns the default highlight color of the reference and footnote marks, a System.Drawing.Color like HighlightColor. To reset the color of one footnote, write footnote.HighlightColor = Footnote.DefaultHighlightColor;.
Handle Footnote Events
The events are declared on the WPF TextControl, and you connect them in XAML like the FootnoteReferenceMarkEntered attribute in the window above. Each handler receives a FootnoteEventArgs whose Footnote property is the footnote concerned:
| Event | Occurs when |
|---|---|
| FootnoteCreated | A footnote has been inserted |
| FootnoteDeleted | A footnote has been deleted |
| FootnoteReferenceMarkEntered | The input position moves onto a reference mark |
| FootnoteReferenceMarkLeft | The input position leaves a reference mark |
| FootnoteSectionActivated | The footnote text at the bottom of a page gets the input position |
| FootnoteSectionDeactivated | The footnote text loses the input position |
The handler below shows the footnote text in the title bar of the window while the cursor is on a reference mark:
private void textControl1_FootnoteReferenceMarkEntered(object sender, FootnoteEventArgs e)
{
Title = "Footnote " + e.Footnote.Number + ": " + e.Footnote.Text;
}
A ServerTextControl, which processes documents without a user interface, has a Footnotes collection as well and raises FootnoteCreated and FootnoteDeleted with the same FootnoteEventArgs. The other four events concern the input position and exist only in the editor controls, such as the WPF TextControl.
Events lists all events of the WPF TextControl.
Next Steps
- Tables of Contents: list the headings of a document with page numbers.
- Headers and Footers: text that repeats at the top and bottom of every page.
- Text and Paragraph Formatting: format the footnote text.
- The blog article Sneak Peek 32.0: Introducing Footnotes: the footnote feature with formatted text and tables.