Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xamarin.Forms.UWP Numeric Keyboard only on soft keyboard

I'm using Xamarin.Forms and want to have a numeric only keyboard for my users to login with a PIN.

I am able to use Xamarin.Forms.Entry.Keyboard = Keyboard.Numeric to force a Numeric keyboard, and this works for iOS, Android and UWP Phones. However, when a user runs the same app on a UWP tablet, like a Microsoft Surface, it displays the full keyboard, which includes Characters along with Numbers.

I want a numeric keyboard to be the only input option to make data validation more simple and secure.

I know I can easily do validation as the text changes to ensure only numbers are present, but is there is a way to only display the number keypad in the soft keyboard for a Xamarin.Forms.Entry on the UWP platform?

like image 634
BrewMate Avatar asked Mar 06 '17 18:03

BrewMate


1 Answers

So I figured this one out myself and wanted to post the answer for future developers. This use case comes from having the soft keyboard displayed on UWP tablets because Xamarin.Forms.Entry utilizes the Windows.UI.Xaml.Controls.TextBox. You can change the InputScope of the TextBox to change the keyboard in UWP as shown in the documentation.

Of course I made the common mistake of not reading the documentation entirely, but rather jumping straight to what keyboards are available. In the docs there is an important line in the beginning:

Important The InputScope property on PasswordBox supports only the Password and NumericPin values. Any other value is ignored.

Oh snap! We're using a TextBox when we really want to use a PasswordBox for UWP. This can easily be achieved with a CustomRenderer and custom entry like below:

Custom Entry:

public class MyCustomPasswordNumericEntry: Xamarin.Forms.Entry
{
}

Custom Renderer:

public class PasswordBoxRenderer : ViewRenderer<Xamarin.Forms.Entry, Windows.UI.Xaml.Controls.PasswordBox>
{
    Windows.UI.Xaml.Controls.PasswordBox passwordBox = new Windows.UI.Xaml.Controls.PasswordBox();
    Entry formsEntry;
    public PasswordBoxRenderer()
    {
        var scope = new InputScope();
        var name = new InputScopeName();

        name.NameValue = InputScopeNameValue.NumericPin;
        scope.Names.Add(name);

        passwordBox.InputScope = scope;
    }

    protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
    {
        base.OnElementChanged(e);

        if (Control == null)
        {
            SetNativeControl(passwordBox);
        }

        if(e.NewElement != null)
        {
            formsEntry = e.NewElement as Entry;

            passwordBox.PasswordChanged += TextChanged;
            passwordBox.FocusEngaged += PasswordBox_FocusEngaged;
            passwordBox.FocusDisengaged += PasswordBox_FocusDisengaged;
        }

        if(e.OldElement != null)
        {
            passwordBox.PasswordChanged -= TextChanged;
        }
    }

    private void PasswordBox_FocusDisengaged(Windows.UI.Xaml.Controls.Control sender, Windows.UI.Xaml.Controls.FocusDisengagedEventArgs args)
    {
        formsEntry.Unfocus();
    }

    private void PasswordBox_FocusEngaged(Windows.UI.Xaml.Controls.Control sender, Windows.UI.Xaml.Controls.FocusEngagedEventArgs args)
    {
        formsEntry.Focus();
    }

    private void TextChanged(object sender, Windows.UI.Xaml.RoutedEventArgs e)
    {
        formsEntry.Text = passwordBox.Password;
    }
}

And lastly make sure we just register the CustomRenderer:

[assembly: Xamarin.Forms.Platform.UWP.ExportRenderer(typeof(MyCustomPasswordNumericEntry), typeof(PasswordBox.UWP.PasswordBoxRenderer))]

Now our MyCustomPasswordNumericEntry will use a Xamarin.Forms.Entry on all platforms, but will use a Windows.UI.Xaml.Controls.PasswordBox on UWP. I also forwarded the basic events on the Xamarin.Forms.Entry to make everything work, but you would also need to have the OnElementPropertyChanged() method update the PasswordBox if there are changes coming from Validation on the Xamarin.Forms.Entry.TextChanged property.

like image 92
BrewMate Avatar answered Oct 19 '22 21:10

BrewMate