Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

[Bug] Entry.Focused event is not fired when EditText.FocusChange is set #8731

Closed
ericc0504 opened this issue Dec 3, 2019 · 5 comments
Closed

Comments

@ericc0504
Copy link

Description

When using PlatformEffect on Android and add one more callback on EditText.FocusChange, another event set from Entry.Focused will not be fired.

Steps to Reproduce

  1. Create an entry and set a callback for Entry.Focused
  2. Create an entry effect and set another callback using "EditText.FocusChange +=[function]"
  3. Set the entry effect for the created entry

Expected Behavior

Both callback from step 1 and step 2 will be called

Actual Behavior

Only the callback from step 2 get called

Basic Information

  • Version with issue:
  • IDE: Visual Studio For Mac 8.3.10 (build 2)
  • Platform Target Frameworks:
    • Android: Android 9.0(Pie), SDK: 1.4.0.65
  • Android Support Library Version: Default
  • Nuget Packages: Xamarin.Forms 4.3.0.991211
  • Emulator: Pixel 2 XL with Android Pie (API 28)

Reproduction Link

EditTextFocusEventBug.zip

@ericc0504 ericc0504 added s/unverified New report that has yet to be verified t/bug 🐛 labels Dec 3, 2019
@PureWeen
Copy link
Contributor

PureWeen commented Dec 3, 2019

@ericc0504 This is a bit of an interesting one :-/

The way Xamarin Android wires up those events is by using a custom OnFocusChangeListener that then propagates that out to FocusChange

But in our ViewRenderer we use our own listener to manage FocusChanged which replaces the Xamarin Android one

Control.OnFocusChangeListener = this;

When you subscribe to the event in your code

editText.FocusChange += EditText_FocusChange;

That causes the Xamarin Android listener to get swapped back in and then our listener no longer works.

I'm not quite sure why we are using a listener here though instead of the events. I'll ask around.

Here's some modified code that should resolve what you are doing

        private void ConfigureControl()
        {
            Element.PropertyChanged += DroidEntryEffect_PropertyChanged;
        }

        private void DroidEntryEffect_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if(e.PropertyName == VisualElement.IsFocusedProperty.PropertyName)
            {
                EditText editText = ((EditText)Control);
                if (editText.HasFocus)
                {
                    Debug.WriteLine("Entry focused. Triggered inside effect.");
                    Application.Current.MainPage.DisplayAlert("Entry focused", "Triggered inside effect", "OK");
                }
            }
        }

@PureWeen
Copy link
Contributor

PureWeen commented Dec 3, 2019

The reason we use a listener here has to do with reducing allocations.

In theory we could subscribe to the FocusChanged event in our code but that would create an allocation for every single subscription so we instead use a listener.

A possible approach to resolve this would be to override OnFocusChanged on all our controls and then propagate out from there.

We could possibly do something like this inside the ViewRenderer code

			if (Control is IHasUsefulFocusOverride theOverride)
				theOverride.SomeAction = this;
			else
				Control.OnFocusChangeListener = this;

@PureWeen PureWeen added e/3 🕒 3 t/enhancement ➕ and removed s/unverified New report that has yet to be verified t/bug 🐛 labels Dec 3, 2019
@PureWeen PureWeen added the up-for-grabs We welcome community contributions to any issue, but these might be a good place to start! label Dec 3, 2019
@ericc0504
Copy link
Author

Thanks for replying swiftly. The provided solution worked on my side. I am looking forward to the enhancement in the ViewRenderer.

@samhouts samhouts added proposal-open a/entry and removed up-for-grabs We welcome community contributions to any issue, but these might be a good place to start! labels Feb 7, 2020
@mkrnic
Copy link

mkrnic commented Dec 10, 2021

I stumbled upon this issue because I had a problem with custom entry renderers that have to do FocusChange stuff. It's not strictly related to this GitHub issue, but it's one of the top results on Google for meaningful "xamarin android entry custom renderer onfocuschange" searches, so it might help someone.

The code below seems to do the job. Save the original listener, invoke it manually.

    private EditText native = null;
    private Android.Views.View.IOnFocusChangeListener focusListener = null;

    protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
    {
        base.OnElementChanged(e);
        ...
        native = Control as EditText;
        ...
        this.focusListener = Control.OnFocusChangeListener;
        native.FocusChange += Native_FocusChange;
        ...
    }


    private void Native_FocusChange(object sender, FocusChangeEventArgs e)
    {
        if (this.focusListener != null)
            this.focusListener.OnFocusChange(native, e.HasFocus);

        if (e.HasFocus)
            ...
        else
            ...
    }

And then you get Focused and Unfocused events fired in Xamarin.

@jfversluis
Copy link
Member

Thanks for this suggestion! As Xamarin.Forms is now in maintenance mode, this will not happen anymore for Xamarin.Forms. We're only adding bugfixes and stability fixes.

If this is still important to you, make sure to check the .NET MAUI repo and see if it's already on the roadmap. If not, feel free to open a discussion to discuss a change first or open an issue with a detailed feature request. Thanks!

@jfversluis jfversluis closed this as not planned Won't fix, can't repro, duplicate, stale Dec 7, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
Archived in project
Development

No branches or pull requests

5 participants