Creating a Custom Keyboard in Xamarin.Forms : Weird Focus Event Behavior

platinum78 21 Reputation points
2021-09-13T15:10:21.32+00:00

I'm working on a personal project to study Xamarin.Forms, and I'm stuck in creating a custom keyboard.
What I want to do is to type characters into <Entry> when some some buttons in the page are clicked, while constantly keeping the focus to the entry.
It's essentially a custom keyboard; the <Entry> does not lose focus, or immediately retakes it.
To implement this, I have set a callback that sets focus to the <Entry> again, and then appends the string allocated to the pressed button to the <Entry>.
The callback function looks like below.

public void KeyPressCallback(string keyText)
{
    // Return focus to input area.
    FormulaViewer.SetFocus(); // This function internally does Entry.Focus()

    // This code internally processes text from clicked button, and allocates it to the Entry.
    _formulaParser.ProcessInput(keyText, FormulaViewer.InputPosition);
    FormulaViewer.InputText = _formulaParser.FormulaString;
}

Alongside, I made a custom renderer of <Entry> that keeps the view from showing soft keyboard at focus, as shown in the below tutorial.
https://theconfuzedsourcecode.wordpress.com/2017/05/19/a-keyboard-disabled-entry-control-in-xamarin-forms/

Now the problem rises.

When I simply tap the entry, only <Focused> event is raised, and the soft keyboard does not show up.
When I press the button, followed by the callback function above, both <Focused> and <FocusChangeRequested> events are raised, and the soft keyboard shows up.

I've been searching a lot to fix this, but I don't see any remedy yet.
Any comment would be greatly helpful.

Developer technologies .NET Xamarin
Developer technologies C#
0 comments No comments
{count} votes

Accepted answer
  1. JarvanZhang 23,971 Reputation points
    2021-09-14T08:30:38.25+00:00

    Hello @platinum78 ,​

    Welcome to our Microsoft Q&A platform!

    I created a basic demo to test the function, and reproduced the issue on my side. The function code of the custom renderer class works fine if we click the 'Entry' directly to make it focus on. The problem will only occur when calling the Focus() method. I check the source code about the method but it doesn't provide the working mechanism. We cannot get how the Focus() method perform in each native platform. If you want to get out this problem, it's suggested to report it to the Xamarin.Forms github repo for help.

    To avoid the problem, here is a workaround which uses the native code to set focus for the entry instead. I add a bool parameter to the custom entry class. Obtain the parameter in the render class to check the value to change the focus status.

    Here is the related code, you could refer to:

       public class CustomEntry : Entry  
       {  
           public static readonly BindableProperty CustomFocusProperty = BindableProperty.Create(nameof(CustomFocus), typeof(bool), typeof(CustomEntry), null);  
         
           public bool CustomFocus  
           {  
               get => (bool)GetValue(CustomFocusProperty);  
               set => SetValue(CustomFocusProperty, value);  
           }  
       }  
         
       [assembly:ExportRenderer(typeof(CustomEntry),typeof(CustomEntryRenderer))]  
       namespace TestApplication_6.Droid  
       {  
           public class CustomEntryRenderer : EntryRenderer  
           {  
               public CustomEntryRenderer(Context context) : base(context)  
               {  
               }  
         
               CustomEntry entry;  
               EditText editText;  
               protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)  
               {  
                   base.OnElementChanged(e);  
         
                   entry = Element as CustomEntry;  
                   editText = Control as EditText;  
                   editText.FocusChange += EditText_FocusChange;  
               }  
         
               private void EditText_FocusChange(object sender, FocusChangeEventArgs e)  
               {  
                   this.Control.ShowSoftInputOnFocus = false;  
               }  
         
               protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)  
               {  
                   base.OnElementPropertyChanged(sender, e);  
         
                   if (entry.CustomFocus)  
                   {  
                       editText.RequestFocus();  
                   }  
                   else  
                   {  
                       editText.ClearFocus();  
                   }  
               }  
           }  
       }  
    

    Change the parameter's value to set focus for the entry:

       public partial class TestPage : CustomPage  
       {  
           public TestPage()  
           {  
               InitializeComponent();  
           }  
           private async void Button_Clicked(object sender, EventArgs e)  
           {  
               entry.CustomFocus = false;  
               entry.Text += "testing";  
               entry.CustomFocus = true;  
           }  
           private void Entry_Focused(object sender, FocusEventArgs e)  
           {  
           }  
       }  
    

    Best Regards,

    Jarvan Zhang


    If the response is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.