UndoRedoManager Class
Records actions and provides asynchronous undo/redo capabilities. Actions can be grouped into transactions and consecutive actions can be merged into a single undo step.
public sealed class UndoRedoManager : INotifyPropertyChangedRemarks
This type is not thread-safe; all operations are expected to run on a single logical flow.
Example
var manager = new UndoRedoManager();
var list = new List<int>();
// Asynchronous execute and unexecute delegates
await manager.RecordActionAsync(
execute: ct => { list.Add(1); return ValueTask.CompletedTask; },
unexecute: ct => { list.RemoveAt(list.Count - 1); return ValueTask.CompletedTask; });
// Synchronous execute and unexecute delegates
await manager.RecordActionAsync(
execute: () => list.Add(2),
unexecute: () => list.RemoveAt(list.Count - 1));
Assert.Equal([1, 2], list);
await manager.UndoAsync();
Assert.Equal([1], list);
await manager.RedoAsync();
Assert.Equal([1, 2], list);- Implements
Constructors
| Name | Description |
|---|---|
| UndoRedoManager() | Initializes a new instance of the UndoRedoManager class with an unbounded history. |
| UndoRedoManager(int) | Initializes a new instance of the UndoRedoManager class keeping at most maxHistoryDepth undo steps. |
UndoRedoManager overloads
UndoRedoManager()
UndoRedoManager.csInitializes a new instance of the UndoRedoManager class with an unbounded history.
public UndoRedoManager()UndoRedoManager(int)
UndoRedoManager.csInitializes a new instance of the UndoRedoManager class keeping at most maxHistoryDepth undo steps.
public UndoRedoManager(int maxHistoryDepth)Parameters
maxHistoryDepthint- The maximum number of undo steps to keep. Once exceeded, the oldest steps are dropped and can no longer be undone.
Exceptions
ArgumentOutOfRangeExceptionmaxHistoryDepthis not strictly positive.
Properties
| Name | Description |
|---|---|
| ActionIsExecuting | Gets a value indicating whether an action is currently being executed, undone, or redone. |
| CanRedo | Gets a value indicating whether UndoRedoManager.RedoAsync would re-execute an action right now. |
| CanUndo | Gets a value indicating whether UndoRedoManager.UndoAsync would revert an action right now. |
| MaxHistoryDepth | Gets the maximum number of undo steps kept in the history. |
| RedoableActions | Gets a snapshot of the actions that can be redone, most recent first. |
| TransactionDepth | Gets the number of transactions that are currently open. |
| UndoableActions | Gets a snapshot of the actions that can be undone, most recent first. |
ActionIsExecuting
UndoRedoManager.csGets a value indicating whether an action is currently being executed, undone, or redone.
public bool ActionIsExecuting { get; }Property value
Remarks
While this is true, any operation that changes the history throws an InvalidOperationException. An action must not record, undo, or redo anything itself.
CanRedo
UndoRedoManager.csGets a value indicating whether UndoRedoManager.RedoAsync would re-execute an action right now.
public bool CanRedo { get; }Property value
Remarks
This is false while a transaction is open or an action is executing, so it can be bound directly to a command's availability.
CanUndo
UndoRedoManager.csGets a value indicating whether UndoRedoManager.UndoAsync would revert an action right now.
public bool CanUndo { get; }Property value
Remarks
This is false while a transaction is open or an action is executing, so it can be bound directly to a command's availability.
MaxHistoryDepth
UndoRedoManager.csRedoableActions
UndoRedoManager.csGets a snapshot of the actions that can be redone, most recent first.
public IReadOnlyList<IUndoRedoAction> RedoableActions { get; }Property value
IReadOnlyList<IUndoRedoAction>
Remarks
The snapshot is rebuilt when the history changes rather than on every access, so an instance obtained earlier stays unchanged.
TransactionDepth
UndoRedoManager.csGets the number of transactions that are currently open.
public int TransactionDepth { get; }Property value
Remarks
Undo, redo and UndoRedoManager.Clear are unavailable while this is greater than zero.
UndoableActions
UndoRedoManager.csGets a snapshot of the actions that can be undone, most recent first.
public IReadOnlyList<IUndoRedoAction> UndoableActions { get; }Property value
IReadOnlyList<IUndoRedoAction>
Remarks
The snapshot is rebuilt when the history changes rather than on every access, so an instance obtained earlier stays unchanged.
Methods
| Name | Description |
|---|---|
| Clear() | Empties both the undo and redo buffers. |
| CreateTransaction(TransactionExecutionMode) | Begins a transaction that groups subsequent recorded actions into a single undo step. |
| RecordActionAsync(IUndoRedoAction, CancellationToken) | Executes an action and records it so it can later be undone. |
| RecordActionAsync(Action, Action, CancellationToken) | Executes a synchronous execute delegate and a synchronous unexecute delegate as a single action and records it so it can later be undone. |
| RecordActionAsync(Action, Func<CancellationToken, ValueTask>, CancellationToken) | Executes a synchronous execute delegate and an asynchronous unexecute delegate as a single action and records it so it can later be undone. |
| RecordActionAsync(Func<CancellationToken, ValueTask>, Action, CancellationToken) | Executes an asynchronous execute delegate and a synchronous unexecute delegate as a single action and records it so it can later be undone. |
| RecordActionAsync(Func<CancellationToken, ValueTask>, Func<CancellationToken, ValueTask>, CancellationToken) | Executes an asynchronous execute delegate and an asynchronous unexecute delegate as a single action and records it so it can later be undone. |
| RedoAsync(CancellationToken) | Re-executes the most recently undone action. Does nothing when there is none. |
| UndoAsync(CancellationToken) | Reverts the most recently recorded action. Does nothing when there is none. |
Clear()
UndoRedoManager.csEmpties both the undo and redo buffers.
public void Clear()Exceptions
InvalidOperationException- An action is currently executing, or a transaction is open.
UndoRedoNotificationException- A
UndoRedoManager.HistoryChangedhandler failed. The history was cleared.
CreateTransaction(TransactionExecutionMode)
UndoRedoManager.csBegins a transaction that groups subsequent recorded actions into a single undo step.
public UndoRedoTransaction CreateTransaction(TransactionExecutionMode mode = TransactionExecutionMode.Deferred)Parameters
modeTransactionExecutionMode- Whether the recorded actions run when the transaction is committed (
TransactionExecutionMode.Deferred, the default) or as they are recorded (TransactionExecutionMode.Immediate).
Returns
UndoRedoTransaction A transaction that must be committed with UndoRedoTransaction.CommitAsync to be kept. Disposing it rolls it back unless it was already completed. Nested transactions must use the same mode as the transaction they are nested in, and must be completed from the innermost out.
Exceptions
InvalidOperationException- An action is currently executing, or
modediffers from the enclosing transaction's mode.
RecordActionAsync overloads
RecordActionAsync(IUndoRedoAction, CancellationToken)
UndoRedoManager.csExecutes an action and records it so it can later be undone.
net10.0
public ValueTask RecordActionAsync(IUndoRedoAction action, CancellationToken cancellationToken = default)net11.0
public ValueTask RecordActionAsync(IUndoRedoAction action, CancellationToken cancellationToken = default)Parameters
actionIUndoRedoAction- The action to execute and record.
cancellationTokenCancellationToken- A token to cancel the execution.
Returns
Exceptions
ArgumentNullExceptionactionisnull.InvalidOperationException- An action is currently executing, or
actionis a transaction that is still open or belongs to another manager. OperationCanceledExceptioncancellationTokenis cancelled.UndoRedoNotificationException- A
UndoRedoManager.HistoryChangedhandler failed. The action was recorded.
RecordActionAsync(Action, Action, CancellationToken)
UndoRedoManager.csExecutes a synchronous execute delegate and a synchronous unexecute delegate as a single action and records it so it can later be undone.
public ValueTask RecordActionAsync(Action execute, Action unexecute, CancellationToken cancellationToken = default)Parameters
executeAction- The delegate invoked to apply the change.
unexecuteAction- The delegate invoked to revert the change.
cancellationTokenCancellationToken- A token to cancel the execution.
Returns
Exceptions
ArgumentNullExceptionexecuteorunexecuteisnull.
RecordActionAsync(Action, Func<CancellationToken, ValueTask>, CancellationToken)
UndoRedoManager.csExecutes a synchronous execute delegate and an asynchronous unexecute delegate as a single action and records it so it can later be undone.
public ValueTask RecordActionAsync(Action execute, Func<CancellationToken, ValueTask> unexecute, CancellationToken cancellationToken = default)Parameters
executeAction- The delegate invoked to apply the change.
unexecuteFunc<CancellationToken, ValueTask>- The delegate invoked to revert the change.
cancellationTokenCancellationToken- A token to cancel the execution.
Returns
Exceptions
ArgumentNullExceptionexecuteorunexecuteisnull.
RecordActionAsync(Func<CancellationToken, ValueTask>, Action, CancellationToken)
UndoRedoManager.csExecutes an asynchronous execute delegate and a synchronous unexecute delegate as a single action and records it so it can later be undone.
public ValueTask RecordActionAsync(Func<CancellationToken, ValueTask> execute, Action unexecute, CancellationToken cancellationToken = default)Parameters
executeFunc<CancellationToken, ValueTask>- The delegate invoked to apply the change.
unexecuteAction- The delegate invoked to revert the change.
cancellationTokenCancellationToken- A token to cancel the execution.
Returns
Exceptions
ArgumentNullExceptionexecuteorunexecuteisnull.
RecordActionAsync(Func<CancellationToken, ValueTask>, Func<CancellationToken, ValueTask>, CancellationToken)
UndoRedoManager.csExecutes an asynchronous execute delegate and an asynchronous unexecute delegate as a single action and records it so it can later be undone.
public ValueTask RecordActionAsync(Func<CancellationToken, ValueTask> execute, Func<CancellationToken, ValueTask> unexecute, CancellationToken cancellationToken = default)Parameters
executeFunc<CancellationToken, ValueTask>- The delegate invoked to apply the change.
unexecuteFunc<CancellationToken, ValueTask>- The delegate invoked to revert the change.
cancellationTokenCancellationToken- A token to cancel the execution.
Returns
Exceptions
ArgumentNullExceptionexecuteorunexecuteisnull.
RedoAsync(CancellationToken)
UndoRedoManager.csRe-executes the most recently undone action. Does nothing when there is none.
net10.0
public ValueTask RedoAsync(CancellationToken cancellationToken = default)net11.0
public ValueTask RedoAsync(CancellationToken cancellationToken = default)Parameters
cancellationTokenCancellationToken- A token to cancel the operation.
Returns
Exceptions
InvalidOperationException- An action is currently executing, or a transaction is open.
OperationCanceledExceptioncancellationTokenis cancelled.AggregateException- A grouped action failed and reverting the actions that already ran failed too.
UndoRedoNotificationException- A
UndoRedoManager.HistoryChangedhandler failed. The action was re-executed.
UndoAsync(CancellationToken)
UndoRedoManager.csReverts the most recently recorded action. Does nothing when there is none.
net10.0
public ValueTask UndoAsync(CancellationToken cancellationToken = default)net11.0
public ValueTask UndoAsync(CancellationToken cancellationToken = default)Parameters
cancellationTokenCancellationToken- A token to cancel the operation.
Returns
Exceptions
InvalidOperationException- An action is currently executing, or a transaction is open.
OperationCanceledExceptioncancellationTokenis cancelled.AggregateException- A grouped action failed to revert and re-applying the actions already reverted failed too.
UndoRedoNotificationException- A
UndoRedoManager.HistoryChangedhandler failed. The action was reverted.
Events
| Name | Description |
|---|---|
| HistoryChanged | Occurs when the undo/redo buffers change (an action is recorded, undone, redone, or the history is cleared). |
| PropertyChanged | Occurs when a property value changes. |
HistoryChanged
Occurs when the undo/redo buffers change (an action is recorded, undone, redone, or the history is cleared).
public event EventHandler? HistoryChangedRemarks
A handler that throws surfaces to the caller as an UndoRedoNotificationException, after the operation itself has completed.
PropertyChanged
Occurs when a property value changes.
public event PropertyChangedEventHandler? PropertyChanged