Skip to content

Feat/searchable combo box - #441

Open
TonyStark172 wants to merge 2 commits into
iNKORE-NET:mainfrom
TonyStark172:feat/SearchableComboBox
Open

Feat/searchable combo box#441
TonyStark172 wants to merge 2 commits into
iNKORE-NET:mainfrom
TonyStark172:feat/SearchableComboBox

Conversation

@TonyStark172

Copy link
Copy Markdown

Adds SearchableComboBox, a ComboBox that shows a search box at the top of its drop-down so long lists can be narrowed by typing.

Picking one item out of several hundred is painful with a plain ComboBox: type-ahead only jumps to a prefix match, and AutoSuggestBox needs a TextChanged handler plus a manual ItemsSource swap before it filters anything. This control filters out of the box with no code, and stays a ComboBox, so SelectedValuePath, ItemTemplate, ItemContainerStyle, IsEditable and the usual bindings keep working.

Behaviour

Out of the box an item matches when its text contains the search text, ignoring case. ItemFilter replaces that rule entirely when something more involved is needed - several members at once, accent folding, or filtering on something other than text.

Two guarantees that are easy to get wrong when rolling this by hand:

  • Filtering is local to the control. A plain collection assigned to ItemsSource is coerced into a private ICollectionView, so typing in the search box never filters a DataGrid or ListView bound to the same collection. An ICollectionView supplied by the caller is honoured as-is.
  • The selected item is never filtered away, so a two-way SelectedItem binding is safe while the user types.

API

Property Purpose
IsSearchEnabled Hides the search box; the control then behaves like a plain ComboBox
SearchText The current query, bindable two-way
SearchBoxPlaceholderText Placeholder inside the search box
NoResultsText Message shown in place of an empty list
SearchMemberPath Member to match against; supports nested paths
ItemFilter Replaces the built-in matching rule
ClearSearchTextOnClose Resets the query when the drop-down closes
SearchBoxStyle Style for the search TextBox
HasNoResults Read-only; drives the empty-state message

Defaults for the two visible strings ship localized for 67 cultures, which is why the diff touches 86 files - 68 of them are .resx.

Notes on three deliberate deviations from ComboBox

  • IsSynchronizedWithCurrentItem defaults to false. Left at null, a Selector synchronises the selection with the view's current item whenever ItemsSource is an ICollectionView - which, after the coercion above, is always. That would select the first item on its own and move the selection around as the user filters.
  • IsTextSearchEnabled defaults to false, so type-ahead does not fight the search box over keystrokes. Set it back to true alongside IsSearchEnabled="False" if you want the plain behaviour.
  • The style declares a VirtualizingStackPanel. See the note at the bottom.

What is included

  • source/iNKORE.UI.WPF.Modern.Controls/Controls/Extended/SearchableComboBox - control, style and strings
  • Gallery page under Windows › Basic Input, next to ComboBox
  • samples/SearchableComboBoxExample - one MVVM drop-down and one wired in code-behind with 5,000 items

Second commit is unrelated

fix(TextBox): keep the clear button glyph visible on hover is a separate defect I ran into while building this, kept in its own commit so it can be split off or dropped.

The clear button's MouseOver and Pressed visual states set their brushes through DiscreteObjectKeyFrame Value="{DynamicResource ...}". A DynamicResource cannot be resolved inside a Storyboard, so the animated value came out null: the glyph lost its Foreground and vanished, and the hover highlight never appeared at all. Reproduced on a plain TextBox on the Gallery's TextBox page, not only inside the new control. Replaced both states with ControlTemplate triggers, where DynamicResource resolves normally and still follows the theme.

Happy to open this as its own PR instead if you prefer.

Two things I found but did not touch

Both are pre-existing and out of scope here, but worth an issue.

ComboBox does not virtualise. DefaultComboBoxStyle sets OverridesDefaultStyle="True", which discards the WPF theme style that declares the virtualising panel, and never declares an ItemsPanel of its own - so ItemsControl's plain StackPanel is used. Measured with 5,000 items:

Items host Containers realised Managed heap
ComboBox StackPanel 5000 / 5000 122 MB
SearchableComboBox (this PR) VirtualizingStackPanel 15 / 5000 2.9 MB

The fix would be the same ItemsPanel setter I added, but it changes item realisation for every ComboBox in the library, so it did not belong in this PR.

ui:ListView realises every item despite declaring a VirtualizingStackPanel and ScrollViewer.CanContentScroll="true" - 5,000 items cost 290 MB. I did not find the root cause; my untested suspicion is that smooth scrolling in ScrollViewerEx overrides CanContentScroll at runtime.
image
image

TonyStark172 and others added 2 commits August 17, 2026 15:08
The delete button's MouseOver and Pressed visual states set their brushes with
DiscreteObjectKeyFrame Value="{DynamicResource ...}". A DynamicResource cannot
be resolved inside a Storyboard, so the animated value came out null: the glyph
lost its Foreground and disappeared, and the hover highlight never showed up at
all. Replaced both states with ControlTemplate triggers, where DynamicResource
resolves normally and still follows the theme.

Affects every TextBox in the library that shows the clear button.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…p-down

Derives from ComboBox and puts a search box at the top of the drop-down so long
lists can be narrowed by typing. An item matches when its text contains the
search text, ignoring case; ItemFilter replaces that rule when something more
involved is needed.

Filtering runs on a view private to the control, so other controls bound to the
same collection are left untouched, and the selected item is never filtered
away, which keeps a two-way SelectedItem binding safe while the user types.

The style declares a VirtualizingStackPanel: a control meant for long lists
cannot fall back to the plain StackPanel that ItemsControl defaults to, which
realises every item.

- source/iNKORE.UI.WPF.Modern.Controls/Controls/Extended/SearchableComboBox:
  control, style, and localized strings for 67 cultures
- Gallery: page under Windows > Basic Input, next to ComboBox
- samples/SearchableComboBoxExample: MVVM and code-behind usage, 5,000 items

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Aris-Offline

Copy link
Copy Markdown
Contributor

Thanks for taking the initiative to contribute to this project! I really appreciate the effort you’ve put into this control and the idea behind it.

That said, I have some concerns about the current styling and overall interaction design. Adding a SearchBox inside the expanded menu creates a rather complex visual hierarchy, and the combination of colors and nested elements feels somewhat cluttered. More importantly, this approach does not seem to align well with the Fluent Design guidelines.

I’d suggest a different approach: instead of placing a separate SearchBox inside the dropdown, the search functionality could be integrated directly into the ComboBox (or AutoSuggestBox, tbd and worth serious consideration) trigger button. This would make the interaction much more compact and intuitive while keeping the control closer to the Fluent Design guidelines.

For the gallery page, I’d also suggest moving it under Extended > Basic Input. This would make it clear that the control is community-contributed rather than part of the core control set.

Regarding your second commit, I’d recommend submitting it as a separate pull request. That will make the changes easier to review and keep the scope of this PR focused.

For the other issues you mentioned in your message, please feel free to continue submitting pull requests as well. Contributions addressing those issues would be very welcome and would help us maintain the project’s stability and overall quality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants