Browse Source

TextBox programmatic Undo/Redo & CanUndo/CanRedo

pull/9490/head
amwx 4 years ago
parent
commit
16f3114e61
  1. 109
      src/Avalonia.Controls/TextBox.cs
  2. 20
      src/Avalonia.Controls/Utils/UndoRedoHelper.cs

109
src/Avalonia.Controls/TextBox.cs

@ -17,7 +17,6 @@ using Avalonia.Controls.Metadata;
using Avalonia.Media.TextFormatting;
using Avalonia.Media.TextFormatting.Unicode;
using Avalonia.Automation.Peers;
using System.Diagnostics;
using Avalonia.Threading;
namespace Avalonia.Controls
@ -166,6 +165,18 @@ namespace Avalonia.Controls
(o, v) => o.UndoLimit = v,
unsetValue: -1);
/// <summary>
/// Defines the <see cref="CanUndo"/> property
/// </summary>
public static readonly DirectProperty<TextBox, bool> CanUndoProperty =
AvaloniaProperty.RegisterDirect<TextBox, bool>(nameof(CanUndo), x => x.CanUndo);
/// <summary>
/// Defines the <see cref="CanRedo"/> property
/// </summary>
public static readonly DirectProperty<TextBox, bool> CanRedoProperty =
AvaloniaProperty.RegisterDirect<TextBox, bool>(nameof(CanRedo), x => x.CanRedo);
/// <summary>
/// Defines the <see cref="CopyingToClipboard"/> event.
/// </summary>
@ -232,6 +243,8 @@ namespace Avalonia.Controls
private bool _canPaste;
private string _newLine = Environment.NewLine;
private static readonly string[] invalidCharacters = new String[1] { "\u007f" };
private bool _canUndo;
private bool _canRedo;
private int _wordSelectionStart = -1;
private int _selectedTextChangesMadeSinceLastUndoSnapshot;
@ -590,6 +603,24 @@ namespace Avalonia.Controls
}
}
/// <summary>
/// Gets a value that indicates whether the undo stack has an action that can be undone
/// </summary>
public bool CanUndo
{
get => _canUndo;
private set => SetAndRaise(CanUndoProperty, ref _canUndo, value);
}
/// <summary>
/// Gets a value that indicates whether the redo stack has an action that can be redone
/// </summary>
public bool CanRedo
{
get => _canRedo;
private set => SetAndRaise(CanRedoProperty, ref _canRedo, value);
}
public event EventHandler<RoutedEventArgs>? CopyingToClipboard
{
add => AddHandler(CopyingToClipboardEvent, value);
@ -943,30 +974,13 @@ namespace Avalonia.Controls
}
else if (Match(keymap.Undo) && IsUndoEnabled)
{
try
{
SnapshotUndoRedo();
_isUndoingRedoing = true;
_undoRedoHelper.Undo();
}
finally
{
_isUndoingRedoing = false;
}
Undo();
handled = true;
}
else if (Match(keymap.Redo) && IsUndoEnabled)
{
try
{
_isUndoingRedoing = true;
_undoRedoHelper.Redo();
}
finally
{
_isUndoingRedoing = false;
}
Redo();
handled = true;
}
@ -1703,5 +1717,60 @@ namespace Avalonia.Controls
}
}
}
/// <summary>
/// Undoes the first action in the undo stack
/// </summary>
public void Undo()
{
if (IsUndoEnabled && CanUndo)
{
try
{
SnapshotUndoRedo();
_isUndoingRedoing = true;
_undoRedoHelper.Undo();
}
finally
{
_isUndoingRedoing = false;
}
}
}
/// <summary>
/// Reapplies the first item on the redo stack
/// </summary>
public void Redo()
{
if (IsUndoEnabled && CanRedo)
{
try
{
_isUndoingRedoing = true;
_undoRedoHelper.Redo();
}
finally
{
_isUndoingRedoing = false;
}
}
}
/// <summary>
/// Called from the UndoRedoHelper when the undo stack is modified
/// </summary>
void UndoRedoHelper<UndoRedoState>.IUndoRedoHost.OnUndoStackChanged()
{
CanUndo = _undoRedoHelper.CanUndo;
}
/// <summary>
/// Called from the UndoRedoHelper when the redo stack is modified
/// </summary>
void UndoRedoHelper<UndoRedoState>.IUndoRedoHost.OnRedoStackChanged()
{
CanRedo = _undoRedoHelper.CanRedo;
}
}
}

20
src/Avalonia.Controls/Utils/UndoRedoHelper.cs

@ -14,6 +14,10 @@ namespace Avalonia.Controls.Utils
public interface IUndoRedoHost
{
TState UndoRedoState { get; set; }
void OnUndoStackChanged();
void OnRedoStackChanged();
}
@ -28,6 +32,10 @@ namespace Avalonia.Controls.Utils
/// </summary>
public int Limit { get; set; } = 10;
public bool CanUndo => _currentNode?.Previous != null;
public bool CanRedo => _currentNode?.Next != null;
public UndoRedoHelper(IUndoRedoHost host)
{
_host = host;
@ -39,6 +47,8 @@ namespace Avalonia.Controls.Utils
{
_currentNode = _currentNode.Previous;
_host.UndoRedoState = _currentNode.Value;
_host.OnUndoStackChanged();
_host.OnRedoStackChanged();
}
}
@ -72,6 +82,8 @@ namespace Avalonia.Controls.Utils
{
while (_currentNode?.Next != null)
_states.Remove(_currentNode.Next);
_host.OnRedoStackChanged();
}
public void Redo()
@ -80,6 +92,8 @@ namespace Avalonia.Controls.Utils
{
_currentNode = _currentNode.Next;
_host.UndoRedoState = _currentNode.Value;
_host.OnRedoStackChanged();
_host.OnUndoStackChanged();
}
}
@ -94,6 +108,9 @@ namespace Avalonia.Controls.Utils
_currentNode = _states.Last;
if (Limit != -1 && _states.Count > Limit)
_states.RemoveFirst();
_host.OnUndoStackChanged();
_host.OnRedoStackChanged();
}
}
@ -101,6 +118,9 @@ namespace Avalonia.Controls.Utils
{
_states.Clear();
_currentNode = null;
_host.OnUndoStackChanged();
_host.OnRedoStackChanged();
}
}
}

Loading…
Cancel
Save