UndoRedoTransaction Class

Groups several actions into a single undoable/redoable unit. Create one with UndoRedoManager.CreateTransaction and commit it to record it as a single step. Committing is all-or-nothing: if one of the actions fails, the actions that already ran are reverted before the exception is propagated.

public sealed class UndoRedoTransaction : IUndoRedoAction, IAsyncDisposable

Remarks

Disposal rolls the transaction back unless UndoRedoTransaction.CommitAsync was called, so leaving the scope because of an exception discards the work instead of applying it. Nested transactions must use the same TransactionExecutionMode as the transaction they are nested in, and must be completed from the innermost out.

Example

var manager = new UndoRedoManager();
var list = new List<string>();

await using (var transaction = manager.CreateTransaction())
{
    await manager.RecordActionAsync(() => list.Add("first"), () => list.Remove("first"));
    await manager.RecordActionAsync(() => list.Add("second"), () => list.Remove("second"));
    await transaction.CommitAsync();
}

Assert.Equal(["first", "second"], list);

// A single UndoAsync reverts both actions
await manager.UndoAsync();
Assert.Empty(list);
Implements

Properties

NameDescription
AllowToMergeWithPreviousGets a value indicating whether this action may be merged with the previous action in the undo buffer.
DescriptionGets a human-readable description of the action, for display in an undo history. Defaults to null.
IsCompletedGets a value indicating whether the transaction has been committed or rolled back.
ModeGets a value indicating when the actions recorded in this transaction are executed.

AllowToMergeWithPrevious

UndoRedoTransaction.cs

Gets a value indicating whether this action may be merged with the previous action in the undo buffer.

public bool AllowToMergeWithPrevious { get; set; }

Property value

bool

Gets a human-readable description of the action, for display in an undo history. Defaults to null.

public string? Description { get; set; }

Property value

string?

Gets a value indicating whether the transaction has been committed or rolled back.

public bool IsCompleted { get; }

Property value

bool

Gets a value indicating when the actions recorded in this transaction are executed.

public TransactionExecutionMode Mode { get; }

Methods

NameDescription
CommitAsync(CancellationToken)Commits the transaction, recording it as a single undo step.
DisposeAsync()Rolls the transaction back if it has not already been committed or rolled back, so leaving the scope because of an exception discards the recorded actions instead of applying them. Call UndoRedoTransaction.CommitAsync to keep them.
Meziantou.Framework.UndoRedo.IUndoRedoAction.ExecuteAsync(CancellationToken)Applies the change encapsulated by this action.
Meziantou.Framework.UndoRedo.IUndoRedoAction.TryToMergeAsync(IUndoRedoAction, CancellationToken)Attempts to merge a following action into this one instead of recording it as a separate step. Useful for long chains of consecutive operations of the same kind (e.g. dragging or typing).
Meziantou.Framework.UndoRedo.IUndoRedoAction.UnExecuteAsync(CancellationToken)Reverts the change previously applied by IUndoRedoAction.ExecuteAsync.
RollbackAsync(CancellationToken)Rolls back the transaction, reverting any actions that were already executed.

CommitAsync(CancellationToken)

UndoRedoTransaction.cs

Commits the transaction, recording it as a single undo step.

public ValueTask CommitAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken
A token to cancel the operation.

Returns

ValueTask

Exceptions

InvalidOperationException
The transaction is already completed, it is not the innermost open transaction, or an action is currently executing.
AggregateException
An action failed and reverting the actions that already ran failed too, leaving them applied.

Rolls the transaction back if it has not already been committed or rolled back, so leaving the scope because of an exception discards the recorded actions instead of applying them. Call UndoRedoTransaction.CommitAsync to keep them.

net10.0

public ValueTask DisposeAsync()

net11.0

public ValueTask DisposeAsync()

Returns

ValueTask

Meziantou.Framework.UndoRedo.IUndoRedoAction.ExecuteAsync(CancellationToken)

UndoRedoTransaction.cs

Applies the change encapsulated by this action.

ValueTask IUndoRedoAction.ExecuteAsync(CancellationToken cancellationToken)

Parameters

cancellationToken CancellationToken

Returns

ValueTask

Meziantou.Framework.UndoRedo.IUndoRedoAction.TryToMergeAsync(IUndoRedoAction, CancellationToken)

UndoRedoTransaction.cs

Attempts to merge a following action into this one instead of recording it as a separate step. Useful for long chains of consecutive operations of the same kind (e.g. dragging or typing).

ValueTask<bool> IUndoRedoAction.TryToMergeAsync(IUndoRedoAction followingAction, CancellationToken cancellationToken)

Parameters

followingAction IUndoRedoAction
The action recorded right after this one.
cancellationToken CancellationToken
A token to cancel the operation.

Returns

ValueTask<bool> true if followingAction was merged into this action; otherwise false.

Remarks

followingAction is in the same applied state as this action: both are already applied at the top level and inside an TransactionExecutionMode.Immediate transaction, and neither is applied inside a TransactionExecutionMode.Deferred one. An implementation must therefore absorb followingAction's effect without applying it.

Returning true discards followingAction: it is never executed nor reverted by the manager again, so this action becomes responsible for applying and reverting both effects from its own IUndoRedoAction.ExecuteAsync and IUndoRedoAction.UnExecuteAsync.

Meziantou.Framework.UndoRedo.IUndoRedoAction.UnExecuteAsync(CancellationToken)

UndoRedoTransaction.cs

Reverts the change previously applied by IUndoRedoAction.ExecuteAsync.

ValueTask IUndoRedoAction.UnExecuteAsync(CancellationToken cancellationToken)

Parameters

cancellationToken CancellationToken

Returns

ValueTask

RollbackAsync(CancellationToken)

UndoRedoTransaction.cs

Rolls back the transaction, reverting any actions that were already executed.

public ValueTask RollbackAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken
A token to cancel the operation.

Returns

ValueTask

Exceptions

InvalidOperationException
The transaction is already completed, it is not the innermost open transaction, or an action is currently executing.
AggregateException
An action failed to revert and re-applying the actions that were already reverted failed too.

Remarks

The transaction stays open if the rollback fails, so it can be retried once the cause is resolved.