# Undo and Redo

> Show undo and redo action names in a WPF menu, group edits into one step with BeginUndoAction and EndUndoAction, call ClearUndo and set IsUndoEnabled in XAML.

- **Product:** TX Text Control .NET for WPF
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET for WPF > Document Editor > Editing Text > Undo and Redo
- **2800 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/editing-text/undo-redo/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/editing-text/undo-redo/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/editing-text/undo-redo/llms-full.txt

---

Ctrl+Z and Ctrl+Y undo and redo changes in the WPF `TextControl` without any code, because the control records every change in its undo buffer. The API adds what an application needs beyond the keys: undo and redo commands for your own menus, the names of the actions, several changes grouped into one step, and a buffer that can be switched off.

The examples use a window with a `TextControl` named `textControl1`, as in [Create Your First WPF Application](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/getting-started/document-editor/first-application/llms-full.txt).

### How the Undo Buffer Works

- **Keys.** Ctrl+Z undoes the last action, and Ctrl+Y restores it.
- **Changes made by code.** Changes through the API are recorded as well, except changes made with the properties and methods of a header or footer, which [HeaderFooter.AddUndoUnit](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/headerfooter/addundounit-method/llms-full.txt) adds to the buffer. Every property set on the current selection is a step, while a prepared `Selection` object assigned once is a single step; see [Selections and Caret Position](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/editing-text/selections/llms-full.txt).
- **Names.** [UndoActionName](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/undoactionname-property/llms-full.txt) and [RedoActionName](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/redoactionname-property/llms-full.txt) return the name of the step that the next undo or redo affects.

### Add Undo and Redo Commands

| Member | Does |
|---|---|
| [Undo](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/undo-method/llms-full.txt) | Undoes the last action |
| [Redo](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/redo-method/llms-full.txt) | Restores the last undone action |
| [CanUndo](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/canundo-property/llms-full.txt), [CanRedo](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/canredo-property/llms-full.txt) | Whether there is an action to undo or redo |
| `UndoActionName`, `RedoActionName` | The name of that action, or `null` if there is none |

The following window has an **Edit** menu with **Undo**, **Redo** and a command of its own, **Insert Closing**, which the next section explains. *MainWindow.xaml*:

```xml
<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="450" Width="800">
    <DockPanel>
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="_Edit" SubmenuOpened="EditMenu_SubmenuOpened">
                <MenuItem x:Name="undoItem" Click="Undo_Click" />
                <MenuItem x:Name="redoItem" Click="Redo_Click" />
                <Separator />
                <MenuItem Header="Insert _Closing" Click="InsertClosing_Click" />
            </MenuItem>
        </Menu>
        <WPF:TextControl x:Name="textControl1" />
    </DockPanel>
</Window>
```

*MainWindow.xaml.cs*, with `SampleApp` replaced by the namespace of your project:

```csharp
using System.Windows;
using TXTextControl;

namespace SampleApp;

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void EditMenu_SubmenuOpened(object sender, RoutedEventArgs e)
    {
        // Show which action the next click undoes or redoes
        undoItem.IsEnabled = textControl1.CanUndo;
        undoItem.Header = textControl1.CanUndo ? "_Undo " + textControl1.UndoActionName : "_Undo";

        redoItem.IsEnabled = textControl1.CanRedo;
        redoItem.Header = textControl1.CanRedo ? "_Redo " + textControl1.RedoActionName : "_Redo";
    }

    private void Undo_Click(object sender, RoutedEventArgs e) => textControl1.Undo();

    private void Redo_Click(object sender, RoutedEventArgs e) => textControl1.Redo();

    private void InsertClosing_Click(object sender, RoutedEventArgs e)
    {
        // Everything until EndUndoAction is undone in one step
        textControl1.BeginUndoAction("Insert Closing");

        try
        {
            textControl1.Selection.Text = "Kind regards,\r\n";

            Selection name = new Selection();
            name.Text = "Tim Typer";
            name.Bold = true;
            textControl1.Selection = name;
        }
        finally
        {
            textControl1.EndUndoAction();
        }
    }
}
```

`SubmenuOpened` updates the two items every time the menu opens: `IsEnabled` grays out an item without an action, and the `Header` shows the name of the action.

### Group Several Changes Into One Step

**Insert Closing** inserts a line of text and a bold name, which would be two separate steps. [BeginUndoAction](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/beginundoaction-method/llms-full.txt) and [EndUndoAction](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/endundoaction-method/llms-full.txt) turn everything between them into one step:

- `BeginUndoAction("Insert Closing")` opens the group and names it. The name can be `null` or an empty string if the menu doesn't show it.
- `Selection.Text` inserts "Kind regards," and ends the paragraph with "\\r\\n". The prepared `Selection` object inserts the bold name.
- `EndUndoAction` in the `finally` block closes the group, even when an exception occurs in between.

Run the application, click **Edit** > **Insert Closing** and open **Edit** again: **Undo Insert Closing** removes both lines with one click. [Search and Replace](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/editing-text/search-replace/llms-full.txt) groups all replacements the same way.

### Clear the Buffer After Loading a Document

When your code loads a document, for example a template, the user shouldn't be able to undo the loading. Call [ClearUndo](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/clearundo-method/llms-full.txt) after [Load](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/load-method/llms-full.txt):

```csharp
private void LoadTemplate(string path)
{
    textControl1.Load(path, StreamType.WordprocessingML);

    // The user cannot undo the loading of the template
    textControl1.ClearUndo();
}
```

### Switch the Buffer Off

The undo buffer takes time and memory. While your code generates a long document in the editor, such as a report, switch it off with [IsUndoEnabled](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/isundoenabled-property/llms-full.txt), and switch it on again before the user edits:

```csharp
textControl1.IsUndoEnabled = false;

try
{
    // Build the document here
}
finally
{
    // Switch undo on again, even if an exception occurred
    textControl1.IsUndoEnabled = true;
}
```

The `finally` block makes sure that an exception doesn't leave the editor without undo.

`IsUndoEnabled` is a dependency property, so it can also be set in XAML (`IsUndoEnabled="False"`) or bound to a view model. The Windows Forms control calls the same setting `AllowUndo`.

Documents that are created without being shown to a user are built with `ServerTextControl` instead, which has no undo history; see [Document Processing](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-processing/llms-full.txt).

### Next Steps

- [Search and Replace](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/editing-text/search-replace/llms-full.txt): replace text in one undo step.
- [Clipboard Operations](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/editing-text/clipboard/llms-full.txt): copy, cut and paste.
- [Keyboard Shortcuts](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/editing-text/keyboard-shortcuts/llms-full.txt): all keys of the editor.
- [Track Changes](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/track-changes/llms-full.txt): record changes for review instead of undoing them.

---

## Nearby

- **Previous:** [Clipboard Operations](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/editing-text/clipboard/llms-full.txt)
- **Next:** [Search and Replace](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/editing-text/search-replace/llms-full.txt)
