12

How to automatically select all text on focus in Entry,Editor,Label? Use Cross Platforms.

Quantity.IsFocused = true; 

No work :(

Ibrahim
  • 949
  • 3
  • 12
  • 21

6 Answers6

19

As mentioned in other answers, if you are using Xamarin Forms 4.2+, you can use the CursorPosition and SelectionLength properties. However, you need to make sure you invoke on the Main/UI thread as all direct manipulation of UI elements must be done there. The app will very likely crash when deployed to a device without doing so, even if it appears to run fine in a simulator.

XAML

<Entry x:Name="MyEntry" Focused="MyEntry_Focused"  />

C#

private void MyEntry_Focused(object sender, FocusEventArgs e)
{
    Dispatcher.BeginInvokeOnMainThread(() =>
    {
        MyEntry.CursorPosition = 0;
        MyEntry.SelectionLength = MyEntry.Text != null ? MyEntry.Text.Length : 0
    });
}

For Xamarin.Forms, you can also use Device.BeginInvokeOnMainThread() rather than Dispatcher. If you're using Xamarin Essentials, there is also MainThread.BeginInvokeOnMainThread() (which does the same as Device.BeginInvokeOnMainThread()).

Xamarin.Forms has a method called Device.BeginInvokeOnMainThread(Action) that does the same thing as MainThread.BeginInvokeOnMainThread(Action). While you can use either method in a Xamarin.Forms app, consider whether or not the calling code has any other need for a dependency on Xamarin.Forms. If not, MainThread.BeginInvokeOnMainThread(Action) is likely a better option.

kiddailey
  • 3,302
  • 3
  • 22
  • 23
  • `MyEntry.Text` could be null if user taps on it very early after it has rendered. Make sure to handle that to prevent crash. – Nik A. Jul 11 '20 at 17:23
  • 1
    It worked for me, in my case was for any Entry. – Aloti Jan 22 '21 at 15:21
  • Why doesn't it work without the Dispatcher.BeginINvokeOnMainThread().. ? – koviroli Oct 17 '21 at 09:24
  • 1
    @ToolmakerSteve Why _wouldn't_ UI events fire on the main thread and consequently call subscribers on that thread? – Bob Sammers Dec 08 '21 at 17:12
  • 1
    @BobSammers - Thanks - You have asked the right question - deleting my incorrect comment about being on the main thread. Since that is a UI event handler, it will indeed be on the main thread. However, until that event returns, MyEntry isn't in a good state to successfully work with its properties. At least those involving selection. (Reason unknown - something inside xamarin or the phone's OS.) `BeginInvoke..` *queues* it to happen as soon as it can (but lets current method return first). I recently observed this on a method that tried to change selected text when an entry gains focus. – ToolmakerSteve Dec 08 '21 at 18:32
  • @ToolmakerSteve (and @kiddailey) Thanks for the explanation. This is not an obvious requirement, or that obvious a fix when problems occur, so the exposure it's getting here should be helpful (it was to me). Is it documented anywhere? – Bob Sammers Dec 14 '21 at 12:00
  • @BobSammers - I have not seen it documented. It was only recently, when testing what worked and what did not work, that I concluded this was the only explanation that fits the facts. I even put in a check IsMainThread to verify that, as expected, its always on main thread. – ToolmakerSteve Dec 14 '21 at 18:05
  • @koviroli Direct UI element manipulations will cause a crash if not done on the main thread. I added clarification to the answer based on your comment, thanks! – kiddailey Dec 14 '21 at 19:38
  • 2
    ToolmakerSteve/BobSammers: This subject feels like it's glossed over a bit in the documentation. Maybe the assumption is that because it's multi-threaded, it should be obvious, who knows. I learned about these details the "hard way" as well which is why I originally added my clarifying answer, so I appreciate all the questions/discussion :) – kiddailey Dec 14 '21 at 19:55
13

1.Add Focused Event.Cs

protected  void Txt_Focussed(object sender, FocusEventArgs e)
{
    txt.CursorPosition = 0;
    txt.SelectionLength = txt.Text.Length;
}

Set focus

protected override void OnAppearing()
{
    base.OnAppearing();
    txt.Focus();
}

XAML Code

<Entry x:Name="txt" Text="155134343" Focused="Txt_Focussed" />
Eequiis
  • 149
  • 10
SAIJAN KP
  • 151
  • 1
  • 5
  • 2
    Xamarin.Form (4.2.0.709249) required – SAIJAN KP Sep 04 '19 at 13:45
  • (tested with 4.2.0.910310) – Dima Apr 02 '20 at 08:18
  • @Dima try my answer – ʞᴉɯ May 19 '20 at 13:14
  • 2
    As mentioned in other answer, for selecting text, make sure to wrap the code in `Dispatcher.BeginInvokeOnMainThread`, otherwise it doesn't work. Another thing to note is that `txt.Text` could be null if user taps on it very early after it has rendered. Make sure to handle that to prevent crash. – Nik A. Jul 11 '20 at 17:24
  • It didnt work for me, it just put the cursor at the end, but the text in not selected – Aloti Dec 09 '20 at 18:14
10

In MainActivity add

public class MyEntryRenderer : EntryRenderer
{
    public MyEntryRenderer(Context ctx) : base(ctx) {}
    protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
    {
        base.OnElementChanged(e);
        if (e.OldElement == null)
        {
            var nativeEditText = (EditText)Control;
            nativeEditText.SetSelectAllOnFocus(true);
        }
    }
}

and to the top add :

[assembly: ExportRenderer (typeof (Entry), typeof (MyEntryRenderer))]
Serve Laurijssen
  • 9,266
  • 5
  • 45
  • 98
Ibrahim
  • 949
  • 3
  • 12
  • 21
  • 2
    what about UWP.how can i create this custom renderer for UWP plateform – Neelam Prajapati Oct 05 '16 at 08:24
  • Tried this and I get reflection error when the view is being instantiated. –  Dec 08 '17 at 12:35
  • This worked for me; ` if (Control != null) { SetNativeControl(Control); Control.SetSelectAllOnFocus(true); } ` –  Dec 08 '17 at 13:57
  • 2
    @Darran - `SetNativeControl(Control)` is redundant; it is essentially saying `Control = Control;`. Just do `if (Control != null) Control.SetSelectAllOnFocus(true);` Or in c# 6 can reduce the `if` test to "null check": Simplifies to: `Control?.SetSelectAllOnFocus(true);` – ToolmakerSteve Jun 24 '18 at 21:39
3

In my case, to make work @SAIJAN KP answer, i made the Focused handler async and awaited a small delay to wait the cursor to appear on Entry:

    private async void Entry_Focused(object sender, FocusEventArgs e)
    {
        await Task.Delay(100);
        entryTest.CursorPosition = x;
        entryTest.SelectionLength = y;
    }

XAML

<Entry x:Name="entryTest" Text="155134343" Focused="Entry_Focused"  />
ʞᴉɯ
  • 5,376
  • 7
  • 52
  • 89
  • Using a delay is a hack approximation to what is accomplished more cleanly via `Dispatcher.BeginInvokeOnMainThread`, as seen in [kiddaily's later answer](https://stackoverflow.com/a/62075324/199364). (Deferring until internal entry-focus code completes.) Bottom line: ONLY rely on a delay, if you can't find a "clean" way to ensure internal code is ready to accept your changes. REASON: Required delay might be different on different devices; it is impossible to guarantee that a delay-based solution will work for all devices. – ToolmakerSteve Jul 22 '22 at 02:38
  • Yes, you are true it's an hack, but the problem here is not related to invoke on main thread the call (indeed not working), but the need to wait some internal xamarin/device ops that i found no other ways to wait. – ʞᴉɯ Nov 05 '22 at 08:52
  • tl;dr: You are correct that "it is already on the main thread". You are wrong in believing that using `BeginInvokeOnMainThread` won't solve the problem. DETAILS: I've tested the problem case shown in question, and used kiddailey's answer, and it solves the problem. The reason it works is because it QUEUES an action to main thread. This GUARANTEES that it runs AFTER the CURRENT UI action (xamarin's internal entry-focus logic) completes. This GUARANTEE is safer than an arbitrarily chosen delay. – ToolmakerSteve Nov 07 '22 at 21:38
3

@kiddailey posted a nice solution, here is a reusable solution based on that:

  1. Create behavior in code behind

    public class SelectContentWhenFocusedBehavior : Behavior<Entry>
    {
        protected override void OnAttachedTo(Entry entry)
        {
            entry.Focused += OnFocused;
            base.OnAttachedTo(entry);
        }
    
        protected override void OnDetachingFrom(Entry entry)
        {
            entry.Focused -= OnFocused;
            base.OnDetachingFrom(entry);
        }
    
        private static void OnFocused(object sender, FocusEventArgs args)
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                Entry myEntry = sender as Entry;
                myEntry.CursorPosition = 0;
                myEntry.SelectionLength = myEntry.Text != null ? myEntry.Text.Length : 0;
            });
        }
    }
    
  2. in your view add the link to the behavior namespace

     xmlns:behav="clr-namespace:MyApp.Resources.Behaviors"
    
  3. Add behavior to your Entry in the view

            <Entry Text="{Binding something, Mode=TwoWay}" Keyboard="Numeric">
                <Entry.Behaviors>
                    <behav:SelectContentWhenFocusedBehavior/>
                </Entry.Behaviors>
            </Entry>
    
Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
G. B.
  • 528
  • 2
  • 15
2

The UWP custom entry renderer could be...

using System.ComponentModel;

using Xamarin.Forms;
using Xamarin.Forms.Platform.UWP;

[assembly: ExportRenderer(typeof(Entry), typeof(myApp.UWP.ExtendedEntryRenderer))]
namespace myApp.UWP
{
    public class ExtendedEntryRenderer : EntryRenderer
    {
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            if (e.PropertyName == nameof(Entry.IsFocused)
                && Control != null && Control.FocusState != Windows.UI.Xaml.FocusState.Unfocused)
                Control.SelectAll();
        }
    }
}
Néstor Sánchez A.
  • 3,848
  • 10
  • 44
  • 68