Feat/searchable combo box - #441
Conversation
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>
|
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 I’d suggest a different approach: instead of placing a separate 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. |
Adds
SearchableComboBox, aComboBoxthat 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, andAutoSuggestBoxneeds aTextChangedhandler plus a manualItemsSourceswap before it filters anything. This control filters out of the box with no code, and stays aComboBox, soSelectedValuePath,ItemTemplate,ItemContainerStyle,IsEditableand the usual bindings keep working.Behaviour
Out of the box an item matches when its text contains the search text, ignoring case.
ItemFilterreplaces 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:
ItemsSourceis coerced into a privateICollectionView, so typing in the search box never filters aDataGridorListViewbound to the same collection. AnICollectionViewsupplied by the caller is honoured as-is.SelectedItembinding is safe while the user types.API
IsSearchEnabledComboBoxSearchTextSearchBoxPlaceholderTextNoResultsTextSearchMemberPathItemFilterClearSearchTextOnCloseSearchBoxStyleTextBoxHasNoResultsDefaults 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
ComboBoxIsSynchronizedWithCurrentItemdefaults tofalse. Left atnull, aSelectorsynchronises the selection with the view's current item wheneverItemsSourceis anICollectionView- 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.IsTextSearchEnableddefaults tofalse, so type-ahead does not fight the search box over keystrokes. Set it back totruealongsideIsSearchEnabled="False"if you want the plain behaviour.VirtualizingStackPanel. See the note at the bottom.What is included
source/iNKORE.UI.WPF.Modern.Controls/Controls/Extended/SearchableComboBox- control, style and stringsComboBoxsamples/SearchableComboBoxExample- one MVVM drop-down and one wired in code-behind with 5,000 itemsSecond commit is unrelated
fix(TextBox): keep the clear button glyph visible on hoveris 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
MouseOverandPressedvisual states set their brushes throughDiscreteObjectKeyFrame Value="{DynamicResource ...}". ADynamicResourcecannot be resolved inside aStoryboard, so the animated value came out null: the glyph lost itsForegroundand vanished, and the hover highlight never appeared at all. Reproduced on a plainTextBoxon the Gallery's TextBox page, not only inside the new control. Replaced both states withControlTemplatetriggers, whereDynamicResourceresolves 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.
ComboBoxdoes not virtualise.DefaultComboBoxStylesetsOverridesDefaultStyle="True", which discards the WPF theme style that declares the virtualising panel, and never declares anItemsPanelof its own - soItemsControl's plainStackPanelis used. Measured with 5,000 items:ComboBoxStackPanelSearchableComboBox(this PR)VirtualizingStackPanelThe fix would be the same
ItemsPanelsetter I added, but it changes item realisation for everyComboBoxin the library, so it did not belong in this PR.ui:ListViewrealises every item despite declaring aVirtualizingStackPanelandScrollViewer.CanContentScroll="true"- 5,000 items cost 290 MB. I did not find the root cause; my untested suspicion is that smooth scrolling inScrollViewerExoverridesCanContentScrollat runtime.