Microsoft-ui-xaml: BUG: AppBarButton click doesn't trigger focus loss on previously focused inputs

Created on 10 Apr 2020  路  17Comments  路  Source: microsoft/microsoft-ui-xaml

// EDIT: initially this was a proposal and it unfolded into a bug. To get the full context please read all comments

Proposal: NumberBox NumberChanged event

Summary

There is currently no way to get value updates from a NumberBox just-in-time as the user types (like you can with a TextBox.TexChanged event).

Rationale

Given the summary above, this forces developers to make workarounds to certain scenarios. Example scenario:
We want to input a value and save the value to a file

  • Given a form with a NumberBox having a Value={x:Bind MyProp, Mode=2way} and ValueChanged="OnValChanged"
  • Given a Button with Click="OnClick" which passes MyProp to a method
  • When I input a number in the NumberBox, and directly after that I click the Button
  • The OnClick triggers before the NumberBox change is picked up, thus passing an outdated value around.

In the case of a TextBox this annoying behavior can be worked around by having a TextChanged event handler which always updates MyProp just-in-time to be ready for being passed to the method invoked by OnClick
In the case of a NumberBox, there's no way to work around this, other than redesigning the UI to have a modal which collects the NumberBox value, and then passes it to the called to be used.

Scope


| Capability | Priority |
| :---------- | :------- |
| Just-in-time NumberBox value changes | Must |

area-NumberBox bug needs-assignee-attention team-Controls

All 17 comments

Just to clarify, the current ValueChanged event is not suitable for you?

Also, when would expect this new event to be raised? As soon as the user has pressed a key?
Couldn't this possibly create a problem if you enable evaluation and the user entered a non numerical key such as "+" or "/" in your use case ?

Hi again @chingucoding

Just to clarify, the current ValueChanged event is not suitable for you?

Actually, in itself, it is suitable, I think I found a bug in...I don't know...UWP...
You see, if I use a Button with the NumberBox, the ValueChanged works as expected: after I input a number in the numbox, I click the button, the numbox loses focus and triggers the ValueChanged, and then the button click event fires.

....but....I don't have a Button in main project, as per the MS UI best practices regarding my usescase, I have a CommandBar, with a AppBarButton. And when I click the AppBarButton the NumberBox actually doesn't lose focus, so the Click event fires and the ValueChanged, well...only fires when I click somewhere else to lose focus, which is not good obviously.

Here's a repo which shows both scenarios (if you're reading this issue in the future, I might have removed the repo by then)
https://github.com/ccornici/potential-uwp-bug
If you wonder, the Click handler method and the method it calls are async because that's how it is in my main project, just wanted to be as close as possible to the main project.

Just run it and:
Scenario 1: Input a value, then directly click on the Button. The desired amount of money is sent.
Scenario 2: Input a different value, then directly click the AppBarButton. An incorrect amount of money is sent.

  • Can you please confirm that this is a bug? Or do I need to fill a new issue for it to be investigated?
  • Also, what would be a nice way to work around this, without doing design (UI) changes?

Thank you for the repro @ccornici !

It seems like this is an issue with the focus behavior. One possible workaround would be to set the focus manually upon button click so the NumberBox updates its value.

I think it's a bug with the AppBarButton as it should get focus upon click, just like a button. @ranjeshj What are your thoughts on this?

@chingucoding something else I noticed:

In the repo above, in MainPage.xaml, if I remove the ValueChanged="NumberBox_ValueChanged", the only way that MainPageViewModel.Amount will be updated now is through the x:Bind present in the xaml.

Given the above, I would expect that when I click the Button (not AppBarButton, which apparently has problems), the Amount is first updated since the NumberBox lost focus, and only then the Click event fires. But the opposite happens. The Click triggers first and the binding update triggers after.

Is this by design?

One possible workaround would be to set the focus manually upon button click so the NumberBox updates its value.

I tried setting focus on pretty much all elements in that XAML and it doesn't work.
Then I tried unsetting focus on the NumBox and it throws an exception as follows:

died

Any other ideas?

In the repo above, in MainPage.xaml, if I remove the ValueChanged="NumberBox_ValueChanged", the only way that MainPageViewModel.Amount will be updated now is through the x:Bind present in the xaml.

Given the above, I would expect that when I click the Button (not AppBarButton, which apparently has problems), the Amount is first updated since the NumberBox lost focus, and only then the Click event fires. But the opposite happens. The Click triggers first and the binding update triggers after.

Is this by design?

I think it is, but I am not really sure when bindings get evaluated. It may be a bug, but I think it's more based on the way bindings work in XAML. But again I am not sure on that.

I tried setting focus on pretty much all elements in that XAML and it doesn't work.
Then I tried unsetting focus on the NumBox and it throws an exception as follows:

Hmm, it seems that setting the focus inside the event handler only raises ValueChanged after it finished the handler it is in. There are two possible workarounds for your situation now I think:

  1. Set flag (e.g. ClickedSendAppBar) inside AppBarButton click function, and change focus. Inside ValueChanged check for that flag and if it is set, do what you would like to do, in the example app send money.
  2. You can find the textbox manually in the UIA tree. For that you could use the following code:

```c#
public MainPage()
{
this.InitializeComponent();
var NumBoxFirstChild = VisualTreeHelper.GetChild(Numbox, 0);

Loaded += MainPage_Loaded;

}

private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var numBoxRootGrid = VisualTreeHelper.GetChild(Numbox,0);
// If you set header, it's 1, otherwise on initial load it is 0
var inputBox = VisualTreeHelper.GetChild(numBoxRootGrid, 0) as TextBox;
if(inputBox == null)
{
inputBox = VisualTreeHelper.GetChild(numBoxRootGrid, 1) as TextBox;
}
inputBox.TextChanged += InputBox_TextChanged;
}

private void InputBox_TextChanged(object sender, TextChangedEventArgs e)
{
Debug.WriteLine($"Value changed to {(sender as TextBox).Text}");
}
```

I wonder if @ranjeshj saw you tagging him above @chingucoding 馃槃

Is the issue that NumberBox is not getting FocusLost in certain cases and we happen to update the value on FocusLost ? Do the elements that are not taking focus normally focusable ?

Hey @ranjeshj @chingucoding . Hope you're both doing good.
Are there any status updates on this bug?

I don't think there is something we can do about the binding timing issues you encounter. However there thing we can do to make the workaround easier for you. I think having a TextChanged event sounds like a reasonable addition to the NumberBox control. Note that input validation only happens on focus lost, not when text get's entered. So in the case of a TextChanged event, there is no guarantee that the current text would be a number. None the less, I am all in for a TextChanged/NumberChanged event. @SavoySchuler What are your thoughts on this?

about the binding timing issues you encounter

Sorry, maybe you forgot the latest context here, this is a bug with the AppBarButton as in when you click it it doesn't trigger the focus loss of..pretty much any previously focused input. That's why it's marked as a bug. You can use the repo as per my instructions above, to get a hands-on refreshment.

So do you still think there's nothing you guys can do about it?

Oh right, I see. Sorry that I forgot the latest changes here, should have read this more carefully.

It's a bit strange that the AppBarButton does not receive focus. @YuliKl @ranjeshj Is this behavior intended? Are there any reasons to not focus it here?
@ccornici This is something that can definitely be fixed, I think the code that causes this behavior is the following line:

https://github.com/microsoft/microsoft-ui-xaml/blob/0a1f27bdf15ea36660a009b04306c786b56f3cf9/dev/CommonStyles/AppBarButton_themeresources.xaml#L114


Are you still interested in a NumberChanged/TextChanged event for the NumberBox control? If not, could you update the title to reflect the actual bug at hand here, i.e. AppBarButton not taking part in focus behavior?

Are there any reasons to not focus it here?

I hope not since it causes serious issues and unexpected/inconsistent behavior 馃槃

AllowFocusOnInteraction defaults to False for AppBarButton (and all its children, for example in a flyout that opens when an AppBarButton is clicked). There are some historical reasons we chose this default, primarily centered around touch scenarios. Can you easily set AllowFocusOnInteraction to True? Does that fix this bug for you?

@YuliKl @chingucoding Setting that property to True fixes the issue and makes the AppBarButton act like the other buttons, thanks! Verified with the test repo above.

Glad to hear that you can workaround the issue by setting AllowFocusOnInteraction to true @ccornici !

@YuliKl If this was by design, is this issue a "no-fix/by design" and should be closed as such then? Or should this behavior be updated given that some controls rely on focus shifts?

Closing this issue since this is by design and there is a straightforward workaround. I assume we don't want to change the default here due to compat.

Was this page helpful?
0 / 5 - 0 ratings