Suppresses auto-focus under certain conditions
In multi-window XAML Islands apps that share a single UI thread for each window, focusing a view on a blurred window causes that window to get focus. Generally speaking, focusing a window should be explicit, and it's likely very rare that you would want a view getting focus to cause the entire window to get focus.
This manifests as problematic in two ways:
- If you have a flyout shown and the flyout gets dismissed because you switch to another window, the parent window for the flyout would steal focus again when react-native-windows attempts to focus the target element.
- If you re-render a view with a TextInput with
autoFocus={true}and the parent window for that TextInput is blurred, the window will steal focus.
This change forces the user to first focus the window and update the active XamlRoot via the XamlUIService::SetXamlRoot API before a view in the window can get focus. In other words, the user has to explicitly focus the window before a programmatic view focus behavior can cause the window to get focused.
Fixes #8251
Microsoft Reviewers: Open in CodeFlow
I'm not sure this fix is the right behavior. The reason that the window steals focus is that it's running on the same thread. if the window were to be running on a different thread, then the window would not get focus (unless you make an explicit choice to allow another thread to get focus), and instead its taskbar icon would flash indicating action is required. So I believe what you are seeing is an artifact of running several [xaml island] windows on the same thread when all of the windows are top level. You might want to scope down the change behind a quirk, as other apps might not want to be artificially limited in not being able to switch focus to another window on the same thread.
The all top level windows should be on different threads is a UWP thing. In win32 its fairly common to have multiple top level windows that are all on the same thread. -- Office included. This does seem like something that XAML should think about with winUI going forward. I dont think the thread check is going to be sufficient. -- But I also dont know how XAML would be able to differentiate between two islands in the same window, and two seperate top windows.
Doing so will be a requirement for Office moving to XAML islands too though. I agree with @asklar that a quirk in RNW for now makes sense. -- But we should open an issue in XAML to think about this more for the future.
@asklar @acoates-ms added a quirk setting. I'll also file a bug on WinUI.
@acoates-ms ping to take another look
@asklar is there a way to tell XAML to only update its internal focus without causing it to activate the window?
This PR seem to completely skip the focus call if the window containing the control doesn't currently have focus. But I don't think that's the behavior we'd want. What we really want is to tell XAML that it should have that control focused when that window is activated. But we dont want to explicitly activate it now. -- This seems some potentially some fallout from moving XAML out of UWP. I suspect we may need to add some more fine grained focus methods to WinUI3?
@acoates-ms - indeed, this does create a "bug" in that the focus state is not correct on the inactive window. I still think this is better than forcing a window to focus.
I'm going through trying to get our list of open PRs down a bit, this one's been open for a while. Now that it's behind a quirk setting, seems like we might be ok to merge? @asklar @acoates-ms, any remaining concerns?
ping @acoates-ms