It's become a hassle to keep writing code for many combo boxes to automatically select the item index of a text value. The problem is that when I assign a text value via code (ComboBox.Text:= 'Some value';
), the item index isn't automatically selected, even though the exact value is already in the list. So I wind up writing code for every combo box to pick the item index by looking up the value. On other occasions, the value assigned might not already be in the list, in which case further handling will add it. But when that value is in the list, I would expect the item index to automatically be assigned.
I can replicate this behavior by dropping a new combo box, assigning some items, and then assigning a text value to it via code. To verify, I click inside this combo box, and press the Up or Down arrow on the keyboard, and it jumps to the beginning of the list. However, if I drop-down the combo box with this assigned value, it then picks that value in the list and assigns the item index. But I shouldn't have to do that.
Auto complete is enabled, and when the user types such a value manually, it does automatically pick this item index. But assigning a value to the Text
property which does in fact exist in the list does not pick that corresponding item index.
Example:
ComboBox.Items.Add('One');
ComboBox.Items.Add('Two');
ComboBox.Items.Add('Three');
ComboBox.Items.Add('Four');
ComboBox.Items.Add('Five');
ComboBox.Text:= 'Five';
I would consider this a bug in the VCL, because even if I never need the item index, the user interface still acts up. In my case, I never need to observe the Item Index, because I send the text values as they are to the server as a string. However, because the index is not assigned, the control itself also does not react the way it should, when user navigates by means other than typing or dropping down the box.
What can I do on a global level to propagate to all my combo box controls (within a given form at least) to make assigning text values via code automatically pick that corresponding value in the list?
You can use an interposer class to change the behavior to something you'll like. E.g.:
type
TComboBox = class(vcl.stdctrls.TComboBox)
protected
procedure WMSetText(var Message: TWMSetText); message WM_SETTEXT;
end;
...
procedure TComboBox.WMSetText(var Message: TWMSetText);
begin
Perform(CB_SELECTSTRING, WPARAM(-1), Message.Text);
inherited;
end;