Add support for setting the default button to WinUI, allowing users to invoke it by pressing enter on another field.
Every windowing framework I've ever used, from VB3, has had the concept of a default button which is invoked by pressing enter when focused on other form fields (for example, a text box). This is analogous to AcceptButton
in WinForms and IsDefault
in WPF.
WinUI should have the ability to set a default button so that pressing enter can invoke the action without needing to trap the key down event to look for enter being pressed.
Update 28/6 - I think it should be possible to also set a cancel button in the same manner. I have updated the rationale and scope accordingly.
| Capability | Priority |
| :---------- | :------- |
| Pressing enter will invoke the default button | Must |
| Pressing escape will invoke the cancel button | Must |
| The default button should be visually distinguishable from other buttons |Should |
| Assign different default / cancel buttons for different controls or control sections (similar to how x:DefaultBindMode works) | Could |
@knightmeister, would you say that a default button is applicable only to forms scenarios? Or are there other types of pages where this would be helpful?
Xaml does provide this default button experience within ContentDialog, but we don't currently have a stand-alone default button.
All the buttons from the various Microsoft frameworks include at least two button styles. Usually the accent colour one is used for this, but there is also an outlined button that could be used to allow it to be further distinguished.
@knightmeister, would you say that a default button is applicable only to forms scenarios? Or are there other types of pages where this would be helpful?
My initial response was to say Forms, but thinking about it there are situations where there are multiple buttons (such as a switchboard) where the user might want to have a default starting button where there are no other form fields present.
Please note I'm just about to amend the initial proposal to include Cancel button, I think that these concepts are used together. While we don't presently have modal dialog support (see #885) if we have the ability to use proper windows, it becomes more relevant.
@knightmeister (and also @mrlacey, @dragocubed, @Poopooracoocoo who have liked this proposal) - I'm still struggling to understand the scenarios when app developers would use this.
@mdtauk, thank you for the controls compilation. Xaml's generic.xaml already includes the AccentButtonStyle
resource which is leveraged by ContentDialog and can be used by apps to draw a visually consistent button. AccentButtonStyle does not provide the "press Enter anywhere to invoke this button" behavior.
Hi @YuliKl
Regarding your points above:
Default button - you've summed it up. One thing I'd point out is that it should be possible to set a default button hierarchically, if possible. For example, buttons in one stack panel may have a different default button to those in another stack panel.
With respect to "Switchboards". This is very common in LOB apps and Access in particular has this concept. Something like this:
So its more than a default style for a button, or even a design for destructive and confirmatory button command - but a behavioural thing.
Is this something that gets added to Content Dialog, to set a default button?
Would this be a property for the Page element to select an initial control focus?
Then if it is a "default" property on every control or every button control, how would it handle having it set on multiple controls?
I was only thinking about forms, or steps in a wizard where 'Next' is the default until reaching the last step when it becomes 'Complete' (or equivalent)
As far as I remember, WinForms and WPF handle the ability to specify defaults differently.
On WinForms, there is a page/window level property that can be used to define the default button.
On WPF, buttons have an IsDefault
property and the last one to set it becomes the default.
My preference is to have WinUI reflect the WPF model because:
DefaultButton
property. (I'm not sure how this would work in practice though--sorry, I haven't thought through all the details here yet.)
- It could be easier to set a default button on arbitrary controls (such as a custom popup) rather than only being available in whatever object has a the
DefaultButton
property. (I'm not sure how this would work in practice though--sorry, I haven't thought through all the details here yet.)In a flyout like TeachingTip, or dialogs, that default would become the default action on Enter. In a form you would suppose it would be the only thing on the page that could be a default.
Outside of those scopes, I guess the last default would be the one picked.
Does the Page XAML object need a "default listener" to keep track of the default? Dialogs and flyouts would need to be able to set this default when they are either modal or the light dismiss focus right?
- It could be easier to set a default button on arbitrary controls (such as a custom popup) rather than only being available in whatever object has a the
DefaultButton
property. (I'm not sure how this would work in practice though--sorry, I haven't thought through all the details here yet.)In a flyout like TeachingTip, or dialogs, that default would become the default action on Enter. In a form you would suppose it would be the only thing on the page that could be a default.
Outside of those scopes, I guess the last default would be the one picked.
Does the Page XAML object need a "default listener" to keep track of the default? Dialogs and flyouts would need to be able to set this default when they are either modal or the light dismiss focus right?
The implications I hadn't thought through were what happens with a custom popup which is still part of the same page (rather than a dialog which has it's own context) when the popup is dismissed. This should (re)set any previous default.
This is the only scenario I can think of where something would need to know what the default was before. Is this what you meant by "default listener"?
For the most part I'd expect it to work by setting an AccessKey (or equivalent) on the button.
Another thought about this proposal:
Would it only work on Button
or could it also work with HyperlinkButton
?
I'd like to see HyperlinkButton supported (so can have purely text based buttons get this functionality without retemplating) but don't think it's appropriate to add it to ButtonBase
as there are things that inherit from it for which this does not make sense (such as CheckBox.)
This is the only scenario I can think of where something would need to know what the default was before. Is this what you meant by "default listener"?
Pretty much yea. There should be a way to override the default contextually, as in ContentDialog or TeachingTip, etc. For as long as the dialog or control has the "focus", it's default would override any others. When it is dismissed, the default returns to what it was previously.
Thank you for helping me understand this proposal. While apps can already implement this behavior today, it requires a good amount of custom code. (ContentDialog is a notable exception, the control has had a DefaultButton
since Windows 1703.)
We won't be able to prioritize this work for a while, but this definitely feels useful. I'm less convinced about the cancel button requirement (again, the cancel behavior is already built into ContentDialog), but the default button feels like a convenient time savings.
We'll revisit this proposal after WinUI 3.
@YuliKl
(again, the cancel behavior is already built into ContentDialog),
I have a content dialog with a AutoSuggestBox, and when it's focused the Enter/Escape shortcut don't work (even though I would like them to). There seems to be no easy way to programmatically trigger primary click or cancellation (see here for a potential solution), is it something that could be exposed in the dialog control?
Most helpful comment
@YuliKl
I have a content dialog with a AutoSuggestBox, and when it's focused the Enter/Escape shortcut don't work (even though I would like them to). There seems to be no easy way to programmatically trigger primary click or cancellation (see here for a potential solution), is it something that could be exposed in the dialog control?