How to read a backspace in an Entry from Xamarin.Forms?

nmdiasnmdias USMember ✭✭
edited June 2017 in Xamarin.Forms

I can't for the life of me capture the backspace! I need to capture a backspace, even if the field is empty. Am I doing something wrong?

public class CustomEntryRenderer: EntryRenderer, Android.Views.View.IOnKeyListener
{
    protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
    {
        base.OnElementChanged(e);

        if (Control == null) 
        {
            return;
        }

        var entry = (CustomEntry)Element;

        Control.SetOnKeyListener(this);

        Control.KeyPress += (s, arg) => { 
            System.Diagnostics.Debug.WriteLine("OnElementChanged KeyPress");
        };

        Control.TextChanged += (s, ev) => { 
            System.Diagnostics.Debug.WriteLine("OnElementChanged TextChanged"); 
        };

        Control.EditorAction += (s, ev) =>
        {
            System.Diagnostics.Debug.WriteLine("EditorAction EditorAction");
        };

        Control.SetOnEditorActionListener(this);


    }

    public override bool OnKeyPreIme(Keycode keyCode, KeyEvent e)
    {
        System.Diagnostics.Debug.WriteLine("OnKeyPreIme");
        return base.OnKeyPreIme(keyCode, e);
    }

    public override bool OnKeyUp(Keycode keyCode, KeyEvent e)
    {
        System.Diagnostics.Debug.WriteLine("OnKeyUp");
        return base.OnKeyUp(keyCode, e);

    }



    protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);

        if (Control == null)
        {
            return;
        }

        var entry = (CustomEntry)Element;

        Control.SetOnKeyListener(this);

        Control.KeyPress += (s, arg) =>
        {
            System.Diagnostics.Debug.WriteLine("OnElementPropertyChanged KeyPress");
        };

        Control.TextChanged += (s, ev) =>
        {
            System.Diagnostics.Debug.WriteLine("OnElementPropertyChanged KeyPress");
        };

        Control.EditorAction += (s, ev) => { 
            System.Diagnostics.Debug.WriteLine("OnElementPropertyChanged EditorAction");
        };

    }

    bool IOnKeyListener.OnKey(Android.Views.View v, Keycode keyCode, KeyEvent e)
    {
        System.Diagnostics.Debug.WriteLine("OnKey");
        return true;
    }


}

Best Answers

  • nmdiasnmdias US ✭✭
    edited June 2017 Accepted Answer

    Got this working, but only on API21+

    public class CustomEntry: Entry
    {
        public delegate void BackspaceEventHandler(object sender, EventArgs e);
    
        public event BackspaceEventHandler OnBackspace;
    
        public CustomEntry() { }
    
        public void OnBackspacePressed() 
        {
            if (OnBackspace != null)
            {
                OnBackspace(null, null);
            }
        }
    }
    
    [assembly: ExportRenderer(typeof(CustomEntry), typeof(CustomEntryRenderer))]
    namespace App.Droid.Renderers
    {
        public class CustomEntryRenderer: EntryRenderer, Android.Text.IInputFilter
        {
            protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
            {
                base.OnElementChanged(e);
    
                if (Control == null) 
                {
                    return;
                }
    
                Control.SetFilters(new IInputFilter[] { this });
    
            }
    
            ICharSequence IInputFilter.FilterFormatted(ICharSequence source, int start, int end, ISpanned dest, int dstart, int dend)
            {
                if (string.IsNullOrWhiteSpace(source.ToString()))
                {
                    var entry = (CustomEntry)Element;
                    entry.OnBackspacePressed();
                }
                return source;
            }
    
        }
    }
    

    and use like this:

    BackspaceEventHandler backspaceEventHandler = (sender, e) => 
    { 
        // Do your thing
    };
    
    entry.OnBackspace += backspaceEventHandler;
    
  • nmdiasnmdias US ✭✭
    edited August 2017 Accepted Answer

    @AnmolModi yes! Here's for iOS also. See if it helps.

    // The Control

    namespace Origination.Renderers
    {
        public class CustomEntry: Entry
        {
            // A delegate type for hooking up change notifications.
            public delegate void BackspaceEventHandler(object sender, EventArgs e);
    
            // An event that clients can use to be notified whenever the
            // elements of the list change.
            public event BackspaceEventHandler OnBackspace;
    
            public CustomEntry() { }
    
            public void OnBackspacePressed() 
            {
                if (OnBackspace != null)
                {
                    OnBackspace(null, null);
                }
            }
    
        }
    }
    

    // The Renderer

    [assembly: ExportRenderer(typeof(CustomEntry), typeof(CustomEntryRenderer))]
    namespace Origination.iOS.Renderers
    {
        public class UIBackwardsTextField: UITextField
        {
            // A delegate type for hooking up change notifications.
            public delegate void DeleteBackwardEventHandler(object sender, EventArgs e);
    
            // An event that clients can use to be notified whenever the
            // elements of the list change.
            public event DeleteBackwardEventHandler OnDeleteBackward;
    
    
            public void OnDeleteBackwardPressed()
            {
                if (OnDeleteBackward != null)
                {
                    OnDeleteBackward(null, null);
                }
            }
    
            public UIBackwardsTextField()
            {
                BorderStyle = UITextBorderStyle.RoundedRect;
                ClipsToBounds = true;
            }
    
            public override void DeleteBackward()
            {
                base.DeleteBackward();
                OnDeleteBackwardPressed();
            }
        }
    
        public class CustomEntryRenderer: EntryRenderer, IUITextFieldDelegate
        {
    
            IElementController ElementController => Element as IElementController;
    
            protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
            {
                if (Element == null) 
                {
                    return;
                }
    
                var entry = (CustomEntry)Element;
                var textField = new UIBackwardsTextField();
                textField.EditingChanged += OnEditingChanged;
                textField.OnDeleteBackward += (sender, a) =>
                {
                    entry.OnBackspacePressed();
                };
    
                SetNativeControl(textField);
    
                base.OnElementChanged(e);
            }
    
            void OnEditingChanged(object sender, EventArgs eventArgs)
            {
                ElementController.SetValueFromRenderer(Entry.TextProperty, Control.Text);
            }
    
        }
    }
    

Answers

  • nmdiasnmdias USMember ✭✭
    edited June 2017 Accepted Answer

    Got this working, but only on API21+

    public class CustomEntry: Entry
    {
        public delegate void BackspaceEventHandler(object sender, EventArgs e);
    
        public event BackspaceEventHandler OnBackspace;
    
        public CustomEntry() { }
    
        public void OnBackspacePressed() 
        {
            if (OnBackspace != null)
            {
                OnBackspace(null, null);
            }
        }
    }
    
    [assembly: ExportRenderer(typeof(CustomEntry), typeof(CustomEntryRenderer))]
    namespace App.Droid.Renderers
    {
        public class CustomEntryRenderer: EntryRenderer, Android.Text.IInputFilter
        {
            protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
            {
                base.OnElementChanged(e);
    
                if (Control == null) 
                {
                    return;
                }
    
                Control.SetFilters(new IInputFilter[] { this });
    
            }
    
            ICharSequence IInputFilter.FilterFormatted(ICharSequence source, int start, int end, ISpanned dest, int dstart, int dend)
            {
                if (string.IsNullOrWhiteSpace(source.ToString()))
                {
                    var entry = (CustomEntry)Element;
                    entry.OnBackspacePressed();
                }
                return source;
            }
    
        }
    }
    

    and use like this:

    BackspaceEventHandler backspaceEventHandler = (sender, e) => 
    { 
        // Do your thing
    };
    
    entry.OnBackspace += backspaceEventHandler;
    
  • AnmolModiAnmolModi USMember ✭✭

    @nmdias Do you have any solution for iOS ?

  • nmdiasnmdias USMember ✭✭
    edited August 2017 Accepted Answer

    @AnmolModi yes! Here's for iOS also. See if it helps.

    // The Control

    namespace Origination.Renderers
    {
        public class CustomEntry: Entry
        {
            // A delegate type for hooking up change notifications.
            public delegate void BackspaceEventHandler(object sender, EventArgs e);
    
            // An event that clients can use to be notified whenever the
            // elements of the list change.
            public event BackspaceEventHandler OnBackspace;
    
            public CustomEntry() { }
    
            public void OnBackspacePressed() 
            {
                if (OnBackspace != null)
                {
                    OnBackspace(null, null);
                }
            }
    
        }
    }
    

    // The Renderer

    [assembly: ExportRenderer(typeof(CustomEntry), typeof(CustomEntryRenderer))]
    namespace Origination.iOS.Renderers
    {
        public class UIBackwardsTextField: UITextField
        {
            // A delegate type for hooking up change notifications.
            public delegate void DeleteBackwardEventHandler(object sender, EventArgs e);
    
            // An event that clients can use to be notified whenever the
            // elements of the list change.
            public event DeleteBackwardEventHandler OnDeleteBackward;
    
    
            public void OnDeleteBackwardPressed()
            {
                if (OnDeleteBackward != null)
                {
                    OnDeleteBackward(null, null);
                }
            }
    
            public UIBackwardsTextField()
            {
                BorderStyle = UITextBorderStyle.RoundedRect;
                ClipsToBounds = true;
            }
    
            public override void DeleteBackward()
            {
                base.DeleteBackward();
                OnDeleteBackwardPressed();
            }
        }
    
        public class CustomEntryRenderer: EntryRenderer, IUITextFieldDelegate
        {
    
            IElementController ElementController => Element as IElementController;
    
            protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
            {
                if (Element == null) 
                {
                    return;
                }
    
                var entry = (CustomEntry)Element;
                var textField = new UIBackwardsTextField();
                textField.EditingChanged += OnEditingChanged;
                textField.OnDeleteBackward += (sender, a) =>
                {
                    entry.OnBackspacePressed();
                };
    
                SetNativeControl(textField);
    
                base.OnElementChanged(e);
            }
    
            void OnEditingChanged(object sender, EventArgs eventArgs)
            {
                ElementController.SetValueFromRenderer(Entry.TextProperty, Control.Text);
            }
    
        }
    }
    
  • AnmolModiAnmolModi USMember ✭✭

    @nmdias thanks a lot , it works like charm :smile:

  • AnmolModiAnmolModi USMember ✭✭

    @nmdias Hello , It's not working for android in some of the device .As far I tested it is working only with Intel x86 (Emulators) processors

  • nmdiasnmdias USMember ✭✭
    edited September 2017

    @AnmolModi said:
    @nmdias Hello , It's not working for android in some of the device .As far I tested it is working only with Intel x86 (Emulators) processors

    The Android solution works only for the API21+ ..for real devices I only tested with Huawei P8 lite and Huawei P9 lite

  • AnmolModiAnmolModi USMember ✭✭
    edited September 2017

    @nmdias Tried it in Nexus 6 & Motorola G2 but it was not working , after tapping on backspace button FilterFormatted event was not triggering . So tried with DispatchKeyEvent it is working even in API 19.

    public override bool DispatchKeyEvent(KeyEvent e)
    {
    if (e.Action == KeyEventActions.Down)
    {
    if (e.KeyCode == Keycode.Del)
    {
    if (string.IsNullOrWhiteSpace(Control.Text))
    {

                        var entry = (CustomEntry)Element;
                        entry.OnBackspacePressed();
                    }
                }
            }
            return base.DispatchKeyEvent(e);
        }
    
  • SmartManSmartMan INMember ✭✭✭

    It is not working suppose i have empty entry then i pressed the delete button in android

Sign In or Register to comment.