0

In my Xamarin Forms app I have a page with an Entry view for entering text. I've wired up the TextChanged event so that the UI dynamically updates as the user enters text, and I want the updated UI to persist if the user presses enter (i.e. the Completed event is triggered) but revert to how it was previously if the user backs out of the view (i.e. the Unfocused event is triggered but not the Completed event).

The complication here is that - at least on Android - Xamarin triggers the Unfocused event first (in both cases) and then the Completed event (only in the case where the user presses enter). So it's difficult to know exactly when to revert the UI changes. This is counter-intuitive to me: when I press enter the view obviously still has focus, so it doesn't make sense for Unfocused to be called first before the Completed.

Some things I've tried and am not happy with:

  • Inside the Unfocused event handler, start a timer for 200ms, and if the Completed event hasn't happened by then assume it's not going to and revert the UI (doesn't seem reliable, 200ms is totally arbitrary).
  • Always revert the UI inside the Unfocused event and then reapply the changes in the Completed event if it is received (ugly, causes UI to flicker, bad performance).
  • Some combination of the above, e.g: start a timer and then revert the UI changes after 200ms, but reapply them if Completed is received after that or cancel the timer if it is received before then (getting a bit complicated).

What's the proper way to do this?

samgak
  • 23,944
  • 4
  • 60
  • 82
  • 1
    [A similar problem](https://forums.xamarin.com/discussion/87705/switching-focus-is-broken-in-entry-completed-event-handler). But I don't think it has a proper solution – Curiosity Jul 26 '17 at 04:35
  • 1
    [This solution](https://stackoverflow.com/a/41521517/7196681), [this](https://forums.xamarin.com/discussion/55183/done-button-not-firing-completed-event-on-entry) and [this](https://stackoverflow.com/a/39582265/7196681) might be helpful – Curiosity Jul 26 '17 at 04:40

1 Answers1

1

Changing your suggestion of timer a little bit. "entryFocus" is an entry name.

CancellationTokenSource source;
private void EntryFocus_Completed(object sender, EventArgs e)
{
    try
    {
        source.Cancel();
    }
    catch { }
}

async private void EntryFocus_Unfocused(object sender, FocusEventArgs e)
{
    source = new CancellationTokenSource();
    try
    {
        await Task.Delay(500, source.Token);
    }
    catch (TaskCanceledException) //completed event requested cancelation
    {
        return;
    }
    catch { } //something is wrong
    entryFocus.Text = "";
}
Yuri S
  • 5,355
  • 1
  • 15
  • 23