Solution 1 :
Editor do not support CursorPosition
Changed event. You could create a custom control EditText
. EditText
provides OnSelectionChanged
event. And add this custom EditText
in EditorRenderer.
MyEditor.cs: Create Editor custom control. And binding the OnSelectionChanged event.
public class MyEditor : Editor
{
public static readonly BindableProperty SelectionChangedProperty =
BindableProperty.Create("SelectionChanged", typeof(EventHandler), typeof(MyEditor), null);
public event EventHandler SelectionChanged;
public void SelectionChange(int preIndex,int currentIndex)
{
EventHandler eventHandler = this.SelectionChanged;
SelectionEventArgs selectionEventArgs = new SelectionEventArgs() { lastPos = preIndex, curPos = currentIndex };
eventHandler?.Invoke((object)this, selectionEventArgs);
}
public class SelectionEventArgs : EventArgs
{
public int lastPos { get; set; }
public int curPos { get; set; }
}
}
EditorRenderer.cs:
[assembly: ExportRenderer(typeof(MyEditor), typeof(XamarinDemo.Droid.EditorRenderer))]
namespace XamarinDemo.Droid
{
class EditorRenderer : Xamarin.Forms.Platform.Android.EditorRenderer, MyEditText.EditTextSelectChange
{
Context _context;
public EditorRenderer(Context context) : base(context)
{
_context = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
MyEditText myEditText = new MyEditText(_context);
myEditText.Text = Element.Text;
myEditText.setEditTextSelectChange(this);
SetNativeControl(myEditText);
}
public void change(int lastPos, int curPos)
{
//Console.WriteLine("lastPos ===" + lastPos + "curPos ====" + curPos);
((MyEditor)Element).SelectionChange(lastPos, curPos);
}
}
}
MyEditText.cs: In Xamarin.Forms Android spefic project, create a EditTextSelectChange
for EditorRenderer to inherit.
class MyEditText :FormsEditText
{
private int mLastPos = 0;
private int mCurPos = 0;
private EditTextSelectChange editTextSelectChange;
public void setEditTextSelectChange(EditTextSelectChange editTextSelectChange)
{
this.editTextSelectChange = editTextSelectChange;
}
public MyEditText(Context context):base(context)
{
}
protected override void OnSelectionChanged(int selStart, int selEnd)
{
base.OnSelectionChanged(selStart, selEnd);
if (this.editTextSelectChange != null)
{
mCurPos = selEnd;
editTextSelectChange.change(mLastPos, mCurPos);
mLastPos = mCurPos;
}
}
public interface EditTextSelectChange
{
void change(int lastPos, int curPos);
}
}
Usage:
<local:MyEditor SelectionChanged="SelectionChange" Text="hakssksksssfsvdsv" />
Code Behind:
public partial class Page13 : ContentPage
{
public Page13()
{
InitializeComponent();
}
private void SelectionChange(object sender, EventArgs e)
{
Console.WriteLine("lastpos =="+ ((SelectionEventArgs)e).lastPos +"curpos =="+ ((SelectionEventArgs)e).curPos);
}
}
Screenshot:
Problem :
I’m currently working on a project that requires alot of text manipulation and i’m trying to create a function that can insert text at the current CursorPosition. I’m using a Editor as my Text Control and i noticed that Xamarin does not provide an implementation for CursorPosition yet.
I found out that the Xamarin developers have this on their backlog but I can’t wait for this as I am on a deadline.
I made my own CustomRenderer for the Editor control and i got CursorPosition working for UWP. When i tried to do the same thing for Android however I noticed that I need to use an the event EventHandler SelectionChanged; in the IFormsEditText interface that is not available to me as they marked the interface internal.
Little snippit of code to display progress:
internal class EditorRenderer : Xamarin.Forms.Platform.Android.EditorRenderer
{
bool _cursorPositionChangePending;
bool _nativeSelectionIsUpdating;
IElementController ElementController => Element as IElementController;
public EditorRenderer(Context context) : base(context) { }
private Editor _editor;
protected override void OnElementChanged(ElementChangedEventArgs<XamarinForms.Editor> e)
{
base.OnElementChanged(e);
_editor = (Editor)Element;
_cursorPositionChangePending = Element.IsSet(Editor.CursorPositionProperty);
// I wanted to do something along the lines of this
//if (Control is IFormsEditText editText)
//{
// editText.SelectionChanged += SelectionChanged;
//}
if (_cursorPositionChangePending)
UpdateCursorSelection();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == Editor.CursorPositionProperty.PropertyName)
{
UpdateCursorSelection();
}
}
void SelectionChanged(object sender, XamarinFormsDroid.SelectionChangedEventArgs e)
{
if (_nativeSelectionIsUpdating || Control == null || Element == null)
return;
int cursorPosition = _editor.CursorPosition;
int selectionStart = EditText.SelectionStart;
if (!_cursorPositionChangePending)
{
var start = cursorPosition;
if (selectionStart != start)
SetCursorPositionFromRenderer(selectionStart);
}
if (!_selectionLengthChangePending)
{
int elementSelectionLength = Math.Min(EditText.Text.Length - cursorPosition, _editor.SelectionLength);
var controlSelectionLength = EditText.SelectionEnd - selectionStart;
if (controlSelectionLength != elementSelectionLength)
SetSelectionLengthFromRenderer(controlSelectionLength);
}
}
Has anyone tried making their own renderer for android with a working implementation for CursorPosition ? Or does anyone have any idea on how this could be realized ? Please let me know.
Comments
Comment posted by Wendy Zang – MSFT
Do you mean you want to set the cursor position in a editor control?
Comment posted by Cinedine
No, I want to know when the cursor has moved in the editor control (for Android). The event i need to use is internal.
Comment posted by Cinedine
But won’t this get rid of all the behavior in the base control ? I got the selection event working like this but for example the TextChanged event wont’ fire if i overwrite this original control.