New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[VDG] Unfocus SearchBar on Escape key #10722
[VDG] Unfocus SearchBar on Escape key #10722
Conversation
{ | ||
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } mainWindow } && Application.Current.FocusManager is { } focusManager) | ||
{ | ||
focusManager.Focus(mainWindow); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mainWindow.Focus()
|
||
if (AssociatedObject is InputElement interactive) | ||
{ | ||
this.WhenAnyValue(x => x.EventRoutingStrategy, x => x.Key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
inputRoot.AddDisposableHandler(InputElement.KeyDownEvent, RootDefaultKeyDown, EventRoutingStrategy) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why listen for changes just not use AddDisposableHandler as in linked behavior
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AddDisposableHandler
creates a subscription, but my the pipeline requires IObservable<T>
. That's why I use OnEvent
instead.
if (AssociatedObject is InputElement element)
{
this.WhenAnyValue(x => x.EventRoutingStrategy, x => x.Key, (strategy, key) => new { Key = key, RoutingStrategy = strategy })
.Select(args => element.OnEvent(InputElement.KeyDownEvent, args.RoutingStrategy).Where(x => x.EventArgs.Key == args.Key))
.Switch()
.Do(_ => Interaction.ExecuteActions(AssociatedObject, Actions, null))
.Subscribe()
.DisposeWith(_disposables);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can discuss which way is better if you show me how you'd implement it using AddDisposableHandler
. I discarded it because the handler it takes doesn't fit well with the reactive paradigm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what @wieslawsoltes meant is it is very unlikely that either EventRoutingStrategy
or Key
will ever change during runtime, so observing for changes is unnecessary and just increases the complexity.
With his suggestion, you could do:
_subscription = element.AddDisposableHandler(InputElement.KeyDownEvent, OnKeyDown, EventRoutingStrategy);
private void OnKeyDown(object? sender, KeyEventArgs e)
{
if (e.Key == Key)
{
Interaction.ExecuteActions(AssociatedObject, Actions, null);
}
}
And also I think it would make sense to have a similar class like DisposingBehavior called DisposingTrigger
. So the disposing could happen as usual and would also simplify a bit as you could do .DisposeWith(disposable);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tACK
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tACK
public void Unfocus() | ||
{ | ||
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } mainWindow }) | ||
{ | ||
mainWindow.Focus(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO we should have a flag like SearchBar.IsActive
and we should just modify that one value. And when it is false, the flyout should close and SearchBar should lose focus.
And everything should control that one flag. It is getting complex to handle every edge case.
Anyway, this is out of the scope of this PR.
Focusing away is the only method to hide the popup. We focus MainWindow so the SearchBar automatically closes its popup.
WalletWasabi.Fluent.Desktop_Cz4FY1zyN2.mp4
I've tried other solutions, but the UX is was bad. Just closing the flyout makes the keyboard caret stay inside without any feedback.
This is a good solution IMHO because, by definition, the searchbar will show the flyout whenever it's focused.
Fixes #10691