diff --git a/samples/MobileSandbox.Android/MainActivity.cs b/samples/MobileSandbox.Android/MainActivity.cs
index bc1be42f12..7a0de74757 100644
--- a/samples/MobileSandbox.Android/MainActivity.cs
+++ b/samples/MobileSandbox.Android/MainActivity.cs
@@ -1,6 +1,7 @@
using System;
using Android.App;
using Android.Content.PM;
+using Android.OS;
using Avalonia;
using Avalonia.Android;
diff --git a/src/Avalonia.Base/Input/TextInput/TextInputMethodClient.cs b/src/Avalonia.Base/Input/TextInput/TextInputMethodClient.cs
index 87f8d7ba97..4abd20f911 100644
--- a/src/Avalonia.Base/Input/TextInput/TextInputMethodClient.cs
+++ b/src/Avalonia.Base/Input/TextInput/TextInputMethodClient.cs
@@ -4,10 +4,6 @@ namespace Avalonia.Input.TextInput
{
public abstract class TextInputMethodClient
{
- private Rect _cursorRectangle;
- private string _surroundingText = "";
- private TextSelection _selection;
-
///
/// Fires when the text view visual has changed
///
@@ -46,87 +42,39 @@ namespace Avalonia.Input.TextInput
///
/// Returns the text around the cursor, usually the current paragraph
///
- public string SurroundingText
- {
- get => _surroundingText;
- set
- {
- var oldValue = _surroundingText;
-
- if (oldValue == value)
- {
- return;
- }
-
- _surroundingText = value;
-
- OnSurroundingTextChanged(oldValue, value);
- }
- }
+ public abstract string SurroundingText { get; }
///
/// Gets the cursor rectangle relative to the TextViewVisual
///
- public Rect CursorRectangle
- {
- get => _cursorRectangle;
- protected set
- {
- var oldvalue = _cursorRectangle;
-
- if (oldvalue == value)
- {
- return;
- }
-
- _cursorRectangle = value;
-
- OnCursorRectangleChanged(oldvalue, value);
- }
- }
+ public abstract Rect CursorRectangle { get; }
///
/// Gets or sets the curent selection range within current surrounding text.
///
- public TextSelection Selection
- {
- get => _selection;
- set
- {
- var oldValue = _selection;
-
- if (oldValue == value)
- {
- return;
- }
-
- _selection = value;
-
- OnSelectionChanged(oldValue, value);
- }
- }
+ public abstract TextSelection Selection { get; set; }
///
/// Sets the non-committed input string
///
public virtual void SetPreeditText(string? preeditText) { }
- protected virtual void OnCursorRectangleChanged(Rect oldValue, Rect newValue)
+ protected virtual void OnTextViewVisualChanged(Visual? oldValue, Visual? newValue)
{
- CursorRectangleChanged?.Invoke(this, EventArgs.Empty);
+ TextViewVisualChanged?.Invoke(this, EventArgs.Empty);
}
- protected virtual void OnTextViewVisualChanged(Visual? oldValue, Visual? newValue)
+ protected virtual void OnCursorRectangleChanged()
{
- TextViewVisualChanged?.Invoke(this, EventArgs.Empty);
+ CursorRectangleChanged?.Invoke(this, EventArgs.Empty);
}
- protected virtual void OnSurroundingTextChanged(string? oldValue, string? newValue)
+ protected virtual void OnSurroundingTextChanged()
{
SurroundingTextChanged?.Invoke(this, EventArgs.Empty);
}
- protected virtual void OnSelectionChanged(TextSelection oldValue, TextSelection newValue)
+ protected virtual void OnSelectionChanged()
{
SelectionChanged?.Invoke(this, EventArgs.Empty);
}
diff --git a/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs b/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs
index 33a0482c68..de4a3c5cf9 100644
--- a/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs
+++ b/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs
@@ -10,10 +10,104 @@ namespace Avalonia.Controls
{
private TextBox? _parent;
private TextPresenter? _presenter;
- private bool _isPropertyChange;
public override Visual TextViewVisual => _presenter!;
+ public override string SurroundingText
+ {
+ get
+ {
+ if (_presenter is null || _parent is null)
+ {
+ return "";
+ }
+
+#if DEBUG
+ if (_parent.CaretIndex != _presenter.CaretIndex)
+ {
+ throw new InvalidOperationException("TextBox and TextPresenter are out of sync");
+ }
+
+ if (_parent.Text != _presenter.Text)
+ {
+ throw new InvalidOperationException("TextBox and TextPresenter are out of sync");
+ }
+#endif
+
+ var lineIndex = _presenter.TextLayout.GetLineIndexFromCharacterIndex(_presenter.CaretIndex, false);
+
+ var textLine = _presenter.TextLayout.TextLines[lineIndex];
+
+ var lineText = GetTextLineText(textLine);
+
+ return lineText;
+ }
+ }
+
+ public override Rect CursorRectangle
+ {
+ get
+ {
+ if (_parent == null || _presenter == null)
+ {
+ return default;
+ }
+
+ var transform = _presenter.TransformToVisual(_parent);
+
+ if (transform == null)
+ {
+ return default;
+ }
+
+ return _presenter.GetCursorRectangle().TransformToAABB(transform.Value);
+ }
+ }
+
+ public override TextSelection Selection
+ {
+ get
+ {
+ if (_presenter is null || _parent is null)
+ {
+ return default;
+ }
+
+ var lineIndex = _presenter.TextLayout.GetLineIndexFromCharacterIndex(_parent.CaretIndex, false);
+
+ var textLine = _presenter.TextLayout.TextLines[lineIndex];
+
+ var lineStart = textLine.FirstTextSourceIndex;
+
+ var selectionStart = Math.Max(0, _parent.SelectionStart - lineStart);
+
+ var selectionEnd = Math.Max(0, _parent.SelectionEnd - lineStart);
+
+ return new TextSelection(selectionStart, selectionEnd);
+ }
+ set
+ {
+ if (_parent is null || _presenter is null)
+ {
+ return;
+ }
+
+ var lineIndex = _presenter.TextLayout.GetLineIndexFromCharacterIndex(_parent.CaretIndex, false);
+
+ var textLine = _presenter.TextLayout.TextLines[lineIndex];
+
+ var lineStart = textLine.FirstTextSourceIndex;
+
+ var selectionStart = lineStart + value.Start;
+ var selectionEnd = lineStart + value.End;
+
+ _parent.SelectionStart = selectionStart;
+ _parent.SelectionEnd = selectionEnd;
+
+ OnSelectionChanged();
+ }
+ }
+
public override bool SupportsPreedit => true;
public override bool SupportsSurroundingText => true;
@@ -38,19 +132,19 @@ namespace Avalonia.Controls
{
oldPresenter.ClearValue(TextPresenter.PreeditTextProperty);
- oldPresenter.CaretBoundsChanged -= OnPresenterCursorRectangleChanged;
+ oldPresenter.CaretBoundsChanged -= (s,e) => OnCursorRectangleChanged();
}
_presenter = presenter;
if (_presenter != null)
{
- _presenter.CaretBoundsChanged += OnPresenterCursorRectangleChanged;
+ _presenter.CaretBoundsChanged += (s, e) => OnCursorRectangleChanged();
}
OnTextViewVisualChanged(oldPresenter, presenter);
- OnPresenterCursorRectangleChanged(this, EventArgs.Empty);
+ OnCursorRectangleChanged();
}
public override void SetPreeditText(string? preeditText)
@@ -63,21 +157,6 @@ namespace Avalonia.Controls
_presenter.SetCurrentValue(TextPresenter.PreeditTextProperty, preeditText);
}
- protected override void OnSelectionChanged(TextSelection oldValue, TextSelection newValue)
- {
- base.OnSelectionChanged(oldValue, newValue);
-
- if (_isPropertyChange)
- {
- return;
- }
-
- if (oldValue != newValue)
- {
- SetParentSelection(newValue);
- }
- }
-
private static string GetTextLineText(TextLine textLine)
{
var builder = StringBuilderCache.Acquire(textLine.Length);
@@ -101,112 +180,17 @@ namespace Avalonia.Controls
return lineText;
}
- private void OnParentTextChanged()
- {
- if (_presenter is null || _parent is null)
- {
- SurroundingText = "";
-
- return;
- }
-
-#if DEBUG
- if (_parent.CaretIndex != _presenter.CaretIndex)
- {
- throw new InvalidOperationException("TextBox and TextPresenter are out of sync");
- }
-
- if (_parent.Text != _presenter.Text)
- {
- throw new InvalidOperationException("TextBox and TextPresenter are out of sync");
- }
-#endif
-
- var lineIndex = _presenter.TextLayout.GetLineIndexFromCharacterIndex(_presenter.CaretIndex, false);
-
- var textLine = _presenter.TextLayout.TextLines[lineIndex];
-
- var lineText = GetTextLineText(textLine);
-
- SurroundingText = lineText;
- }
-
- private void OnPresenterCursorRectangleChanged(object? sender, EventArgs e)
- {
- if (_parent == null || _presenter == null)
- {
- CursorRectangle = default;
-
- return;
- }
-
- var transform = _presenter.TransformToVisual(_parent);
-
- if (transform == null)
- {
- CursorRectangle = default;
-
- return;
- }
-
- CursorRectangle = _presenter.GetCursorRectangle().TransformToAABB(transform.Value);
- }
-
private void OnParentPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
- _isPropertyChange = true;
-
if (e.Property == TextBox.TextProperty)
{
- OnParentTextChanged();
+ OnSurroundingTextChanged();
}
if (e.Property == TextBox.SelectionStartProperty || e.Property == TextBox.SelectionEndProperty)
{
- Selection = GetParentSelection();
- }
-
- _isPropertyChange = false;
- }
-
- private TextSelection GetParentSelection()
- {
- if (_presenter is null || _parent is null)
- {
- return default;
- }
-
- var lineIndex = _presenter.TextLayout.GetLineIndexFromCharacterIndex(_parent.CaretIndex, false);
-
- var textLine = _presenter.TextLayout.TextLines[lineIndex];
-
- var lineStart = textLine.FirstTextSourceIndex;
-
- var selectionStart = Math.Max(0, _parent.SelectionStart - lineStart);
-
- var selectionEnd = Math.Max(0, _parent.SelectionEnd - lineStart);
-
- return new TextSelection(selectionStart, selectionEnd);
- }
-
- private void SetParentSelection(TextSelection selection)
- {
- if (_parent is null || _presenter is null)
- {
- return;
+ OnSelectionChanged();
}
-
- var lineIndex = _presenter.TextLayout.GetLineIndexFromCharacterIndex(_parent.CaretIndex, false);
-
- var textLine = _presenter.TextLayout.TextLines[lineIndex];
-
- var lineStart = textLine.FirstTextSourceIndex;
-
- var selectionStart = lineStart + selection.Start;
- var selectionEnd = lineStart + selection.End;
-
- _parent.SelectionStart = selectionStart;
- _parent.SelectionEnd = selectionEnd;
}
}
}