diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 2506fd0624..a07aeb16f1 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -18,6 +18,15 @@ namespace Avalonia.Controls { public class TextBox : TemplatedControl, UndoRedoHelper.IUndoRedoHost { + public static KeyGesture CutGesture { get; } = AvaloniaLocator.Current + .GetService()?.Cut.FirstOrDefault(); + + public static KeyGesture CopyGesture { get; } = AvaloniaLocator.Current + .GetService()?.Copy.FirstOrDefault(); + + public static KeyGesture PasteGesture { get; } = AvaloniaLocator.Current + .GetService()?.Paste.FirstOrDefault(); + public static readonly StyledProperty AcceptsReturnProperty = AvaloniaProperty.Register(nameof(AcceptsReturn)); @@ -103,6 +112,21 @@ namespace Avalonia.Controls public static readonly StyledProperty RevealPasswordProperty = AvaloniaProperty.Register(nameof(RevealPassword)); + + public static readonly DirectProperty CanCutProperty = + AvaloniaProperty.RegisterDirect( + nameof(CanCut), + o => o.CanCut); + + public static readonly DirectProperty CanCopyProperty = + AvaloniaProperty.RegisterDirect( + nameof(CanCopy), + o => o.CanCopy); + + public static readonly DirectProperty CanPasteProperty = + AvaloniaProperty.RegisterDirect( + nameof(CanPaste), + o => o.CanPaste); struct UndoRedoState : IEquatable { @@ -126,6 +150,9 @@ namespace Avalonia.Controls private UndoRedoHelper _undoRedoHelper; private bool _isUndoingRedoing; private bool _ignoreTextChanges; + private bool _canCut; + private bool _canCopy; + private bool _canPaste; private string _newLine = Environment.NewLine; private static readonly string[] invalidCharacters = new String[1] { "\u007f" }; @@ -378,6 +405,33 @@ namespace Avalonia.Controls SelectionStart = SelectionEnd = CaretIndex; } + /// + /// Property for determining if the Cut command can be executed. + /// + public bool CanCut + { + get { return _canCut; } + private set { SetAndRaise(CanCutProperty, ref _canCut, value); } + } + + /// + /// Property for determining if the Copy command can be executed. + /// + public bool CanCopy + { + get { return _canCopy; } + private set { SetAndRaise(CanCopyProperty, ref _canCopy, value); } + } + + /// + /// Property for determining if the Paste command can be executed. + /// + public bool CanPaste + { + get { return _canPaste; } + private set { SetAndRaise(CanPasteProperty, ref _canPaste, value); } + } + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { _presenter = e.NameScope.Get("PART_TextPresenter"); @@ -395,9 +449,19 @@ namespace Avalonia.Controls if (change.Property == TextProperty) { UpdatePseudoclasses(); + UpdateCommandStates(); } } + private void UpdateCommandStates() + { + var text = GetSelection(); + var isNullOrEmpty = string.IsNullOrEmpty(text); + CanCopy = !isNullOrEmpty; + CanCut = !isNullOrEmpty && !IsReadOnly; + CanPaste = !IsReadOnly; + } + protected override void OnGotFocus(GotFocusEventArgs e) { base.OnGotFocus(e); @@ -412,6 +476,8 @@ namespace Avalonia.Controls SelectAll(); } + UpdateCommandStates(); + _presenter?.ShowCaret(); } @@ -424,7 +490,9 @@ namespace Avalonia.Controls ClearSelection(); RevealPassword = false; } - + + UpdateCommandStates(); + _presenter?.HideCaret(); } @@ -467,19 +535,31 @@ namespace Avalonia.Controls return text; } - private async void Copy() + public async void Cut() { + var text = GetSelection(); + if (text is null) return; + + _undoRedoHelper.Snapshot(); + Copy(); + DeleteSelection(); + _undoRedoHelper.Snapshot(); + } + + public async void Copy() + { + var text = GetSelection(); + if (text is null) return; + await ((IClipboard)AvaloniaLocator.Current.GetService(typeof(IClipboard))) - .SetTextAsync(GetSelection()); + .SetTextAsync(text); } - private async void Paste() + public async void Paste() { var text = await ((IClipboard)AvaloniaLocator.Current.GetService(typeof(IClipboard))).GetTextAsync(); - if (text == null) - { - return; - } + + if (text is null) return; _undoRedoHelper.Snapshot(); HandleTextInput(text); @@ -518,23 +598,18 @@ namespace Avalonia.Controls { if (!IsPasswordBox) { - _undoRedoHelper.Snapshot(); - Copy(); - DeleteSelection(); - _undoRedoHelper.Snapshot(); + Cut(); } handled = true; } else if (Match(keymap.Paste)) { - Paste(); handled = true; } else if (Match(keymap.Undo)) { - try { _isUndoingRedoing = true; diff --git a/src/Avalonia.Themes.Default/TextBox.xaml b/src/Avalonia.Themes.Default/TextBox.xaml index 9c1914de66..d0b0c044f5 100644 --- a/src/Avalonia.Themes.Default/TextBox.xaml +++ b/src/Avalonia.Themes.Default/TextBox.xaml @@ -1,4 +1,11 @@ + + + + + + +