AutoSuggestBox is a text box with a list that comes up while the user types, the way a search field offers what you might have meant. It derives from ComboBox, so everything a ComboBox can do it can do too, and it wears the same clothes as every other MahApps text control.
AutoSuggestBox is on develop and ships with the next release. It is not in 2.4.11.
<mah:AutoSuggestBox x:Name="ArtistBox"
Width="300"
DisplayMemberPath="Name"
QuerySubmitted="OnQuerySubmitted"
TextChanged="OnTextChanged"
mah:TextBoxHelper.ClearTextButton="True"
mah:TextBoxHelper.Watermark="Artist" />
private void OnTextChanged(object sender, RoutedEventArgs e)
{
if (((AutoSuggestBoxTextChangedEventArgs)e).Reason != AutoSuggestionBoxTextChangeReason.UserInput)
{
return;
}
this.ArtistBox.ItemsSource = this.artists
.Where(artist => artist.Name.StartsWith(this.ArtistBox.Text, StringComparison.CurrentCultureIgnoreCase))
.Take(10)
.ToList();
}
private void OnQuerySubmitted(object sender, RoutedEventArgs e)
{
var args = (AutoSuggestBoxQuerySubmittedEventArgs)e;
this.Search(args.ChosenSuggestion as Artist, args.QueryText);
}
How it works
The box does not filter anything. It says that the text changed and who changed it, and the application answers by filling ItemsSource with whatever it thinks fits. That is the whole contract, and it is deliberate: matching, sorting, casing, accents and the question of what counts as a hit all belong where the data is, not in a set of filter modes here. It is also how WinUI's AutoSuggestBox works.
So there is no FilterMode, no CustomFilter and no SearchMemberPath. There is a TextChanged event and your own code.
Properties
The control adds none of its own. Everything it needs a ComboBox already has:
| Property | |
|---|---|
ItemsSource, ItemTemplate, ItemTemplateSelector |
the suggestions and how they are drawn |
DisplayMemberPath |
which member of a suggestion is shown, and written into the text |
TextSearch.TextPath |
the same, when the shown text and the written text differ |
Text |
what stands in the box, two-way by default |
SelectedItem |
the suggestion the user is on, null while they are only typing |
IsDropDownOpen |
whether the list is up; set it yourself to open or close it |
MaxDropDownHeight |
how tall the list may get |
Three properties are set for you and are not meant to be changed: IsEditable is True, IsTextSearchEnabled is False, so WPF does not complete the text behind your back while the user is still typing, and StaysOpenOnEdit is True, so the list stays up between keystrokes.
Events
| Event | Arguments | Raised |
|---|---|---|
TextChanged |
AutoSuggestBoxTextChangedEventArgs |
after the text changed, whoever changed it |
SuggestionChosen |
AutoSuggestBoxSuggestionChosenEventArgs |
when the user lands on a suggestion, by arrow key or by click |
QuerySubmitted |
AutoSuggestBoxQuerySubmittedEventArgs |
when the user is done, by Enter or by clicking a suggestion |
All three are bubbling routed events, so they can be handled further up or attached from a style.
AutoSuggestBoxTextChangedEventArgs.Reason says who wrote the text:
| Reason | |
|---|---|
UserInput |
the user typed, and this is the one worth new suggestions |
ProgrammaticChange |
code or a binding set Text |
SuggestionChosen |
the user picked a suggestion and the box wrote it in |
Check the reason before you go looking for suggestions. Picking a suggestion writes it into the text box, which changes the text again. Answering that with a fresh search finds the item the box has just offered, replaces the list, and the selection and the text go with it. The box keeps the three cases apart so that a single if at the top of the handler is all it takes.
AutoSuggestBoxQuerySubmittedEventArgs carries both halves of the answer:
| Member | Type | |
|---|---|---|
QueryText |
string? |
what stands in the box |
ChosenSuggestion |
object? |
the suggestion the user picked, or null if they only typed |
AutoSuggestBoxSuggestionChosenEventArgs.SelectedItem is the suggestion the user landed on.
When the list shows itself
The list comes up once there is text in the box and there is something to show, and it goes away when either of those stops being true. An empty list is never shown, because an empty popup is a sliver of border under a text box and nothing else.
Suggestions do not have to be there by the time the text changes. An application that goes off to a database or a service hands them over later, and the list comes up when they arrive:
private async void OnTextChanged(object sender, RoutedEventArgs e)
{
if (((AutoSuggestBoxTextChangedEventArgs)e).Reason != AutoSuggestionBoxTextChangeReason.UserInput)
{
return;
}
var query = this.Box.Text;
var hits = await this.service.SuggestAsync(query).ConfigureAwait(true);
// the user has typed on in the meantime, so this answer is stale
if (this.Box.Text != query)
{
return;
}
this.Box.ItemsSource = hits;
}
There is no delay property. Where a request per keystroke is too much, hold the keystrokes back in the handler:
private readonly DispatcherTimer typingPause = new() { Interval = TimeSpan.FromMilliseconds(300) };
Restart that timer on every UserInput, and do the asking in its Tick.
Picking a suggestion
A suggestion the user lands on is written into the text box, and what gets written is the text a ComboBox would write, so DisplayMemberPath and TextSearch.TextPath decide it for objects. Every way of choosing one is a deliberate act, so there is no switch to keep the choice out of the box. Where the box should read differently afterwards, empty for instance, QuerySubmitted is the place to set it.
The keyboard
| Key | |
|---|---|
| ↓ ↑ | walk the list. The box takes what they land on and marks it, so typing on replaces it and starts a fresh query |
| Enter | submit. With a suggestion walked to, ChosenSuggestion is that suggestion; otherwise the typed text is the whole query |
| Esc | close the list and submit nothing |
Esc does not bring back what the user had typed before they walked the list. That is how an editable ComboBox has always behaved and the suggestion box does not change it.
Styling
The control is styled as MahApps.Styles.AutoSuggestBox, which stands on MahApps.Styles.ComboBox, so the brushes, the fonts, the focus and mouse-over borders and the validation template are the ones every other MahApps input control uses. The template is its own: there is nothing to drop down by hand here, so there is no arrow, and the spot it would sit in takes one button instead.
The usual TextBoxHelper properties are passed through to the inner text box:
| Property | |
|---|---|
Watermark, WatermarkAlignment, WatermarkTrimming |
the hint in an empty box |
UseFloatingWatermark |
let the hint rise above the text once there is text |
ClearTextButton |
put a clear button in the button spot |
ButtonCommand, ButtonContent, ButtonTemplate, ButtonWidth |
or put your own button there, a magnifier for instance |
ComboBoxHelper.MaxLength and ComboBoxHelper.CharacterCasing reach the text box as well.
With neither ClearTextButton nor a ButtonCommand set, the button spot collapses and the text takes the whole width.
The Windows looks
There are two more styles, MahApps.Styles.AutoSuggestBox.Win10 and MahApps.Styles.AutoSuggestBox.WinUI, and each of them is the combo box of that set with the chevron taken off it. That is the point: a suggestion box and a combo box standing next to each other in a form are the same height and the same colour, down to the fill, the frame, the padding and the delete button.
<mah:AutoSuggestBox Width="300"
Style="{DynamicResource MahApps.Styles.AutoSuggestBox.WinUI}"
mah:TextBoxHelper.ClearTextButton="True"
mah:TextBoxHelper.Watermark="Artist" />
The Windows 10 one turns white with an accent frame once the caret is in it. The WinUI one rounds its corners and draws the border a touch stronger along the bottom edge, which turns into the accent there instead. That edge is a border of its own, two units thick either way, so a box with the caret in it is as tall as the one beside it and nothing under it moves.
The list follows along. It is the drop-down of that set, the rows and all: square rows picked out with the accent turned right down in the Windows 10 one, rounded tiles with a short accent bar along the left edge of the row that is picked in the WinUI one. The delete button of both sets waits until there is something to delete, and a box that is switched off says so with its colours rather than with a veil over it.
Merging Styles/Win10/Controls.xaml or Styles/WinUI/Controls.xaml applies the matching style to every suggestion box in that part of the tree. Win 10 (UWP) and WinUI have the whole set.
What a client is told
The box reports itself as an AutoSuggestBox and as a combo box control type, and hands over its text as a value, so a test or a screen reader gets the box rather than the text field inside it.
Related
MultiSelectionComboBox where the user picks several items rather than typing free text, ComboBox for the box this one is cut from, TextBoxHelper for the watermark and the buttons, validation for the error treatment.