Let's say we have the following code in a Windows application:
ComboBox comboBox = new ComboBox()
{
AutoCompleteMode = AutoCompleteMode.SuggestAppend,
AutoCompleteSource = AutoCompleteSource.ListItems,
DataSource = new string[] { "", "Ark", "Boat", "Bucket" },
DropDownStyle = ComboBoxStyle.DropDownList
};
this.Controls.Add(comboBox);
TextBox textBox = new TextBox()
{
Left = comboBox.Right,
Top = comboBox.Top,
ReadOnly = true
};
textBox.DataBindings.Add("Text", comboBox, "SelectedValue");
this.Controls.Add(textBox);
No magic here, just a ComboBox
bound to a list of strings. The TextBox
displays the SelectedValue
of the ComboBox
.
I'm getting unexpected behavior when I type "Bucket" into the ComboBox
and tab away. For some reason the ComboBox
displays "Boat" but the TextBox
displays "Bucket". I would expect them both to display "Bucket".
It behaves as expected if I change the DropDownStyle
to DropDown
, but I don't want users to be able to type anything they want. They should only be able to type items that are in the list.
Even more interesting is that, after typing "Bucket" and tabbing away, if I type "Bucket" again it will display "Bucket" in both. If I make a third attempt, it goes back to "Boat" for the ComboBox
and "Bucket" for the `TextBox'. So it seems like it's cycling through all the B's.
I didn't notice this until I upgraded from XP to Windows 7 recently. I don't see how that could have anything to do with this, but I'm throwing it out anyway.
If this behavior is correct, can anyone tell me what I should be doing to achieve my expected behavior?
UPDATE It would seem this is related to Windows 7. Everything behaves as expected in Windows XP Mode. Can anyone else running Windows 7 try my code and verify that I'm not crazy?
A workaround could be changing the DropDownStyle
to DropDown
and adding the following:
comboBox.Validating += new CancelEventHandler((o, e) =>
{
e.Cancel = (comboBox.DataSource as string[]).Contains(comboBox.Text) == false;
});
That will allow users to type anything, but it won't let them tab away from the control unless they typed a valid item.
Still, not happy with the behavior changing from XP to Win 7.
This hotfix will solve this issue.
I ran into this myself and found a few workarounds. In the end I rolled my own solution as a ComboBox subclass:
//as noted here: https://connect.microsoft.com/VisualStudio/feedback/details/523272/combobox-does-not-display-selectedvalue-to-user-in-windows-7
//Windows 7 has issues with ComboBoxStyle.DropDownList mixed with AutoCompleteMode.Append or AutoCompleteMode.SuggestAppend
//this class seeks to address those problems
public class BetterComboBox : ComboBox
{
private int _windows7CorrectedSelectedIndex = -1;
private int? _selectedIndexWhenDroppedDown = null;
protected override void OnDropDown(EventArgs e)
{
_selectedIndexWhenDroppedDown = SelectedIndex;
base.OnDropDown(e);
}
private bool _onDropDownClosedProcessing = false;
protected override void OnDropDownClosed(EventArgs e)
{
if (_selectedIndexWhenDroppedDown != null && _selectedIndexWhenDroppedDown != SelectedIndex)
{
try
{
_onDropDownClosedProcessing = true;
OnSelectionChangeCommitted(e);
}
finally
{
_onDropDownClosedProcessing = false;
}
}
base.OnDropDownClosed(e);
if (SelectedIndex != _windows7CorrectedSelectedIndex)
{
SelectedIndex = _windows7CorrectedSelectedIndex;
OnSelectionChangeCommitted(e);
}
}
protected override void OnSelectionChangeCommitted(EventArgs e)
{
if (!_onDropDownClosedProcessing) _windows7CorrectedSelectedIndex = SelectedIndex;
_selectedIndexWhenDroppedDown = null;
base.OnSelectionChangeCommitted(e);
}
protected override void OnSelectedIndexChanged(EventArgs e)
{
bool alreadyMatched = true;
if (_windows7CorrectedSelectedIndex != SelectedIndex)
{
_windows7CorrectedSelectedIndex = SelectedIndex;
alreadyMatched = false;
}
base.OnSelectedIndexChanged(e);
//when not dropped down, the SelectionChangeCommitted event does not fire upon non-arrow keystrokes due (I suppose) to AutoComplete behavior
//this is not acceptable for my needs, and so I have come up with the best way to determine when to raise the event, without causing duplication of the event (alreadyMatched)
//and without causing the event to fire when programmatic changes cause SelectedIndexChanged to be raised (_processingKeyEventArgs implies user-caused)
if (!DroppedDown && !alreadyMatched && _processingKeyEventArgs) OnSelectionChangeCommitted(e);
}
private bool _processingKeyEventArgs = false;
protected override bool ProcessKeyEventArgs(ref Message m)
{
try
{
_processingKeyEventArgs = true;
return base.ProcessKeyEventArgs(ref m);
}
finally
{
_processingKeyEventArgs = false;
}
}
}
I created my own solution because I didn't think deploying a hotfix to all users computers was reasonable or manageable. However the hotfix problem description describes my problem. See list below for example:
Acorn
Apple
Bad
Bed
Brick
Cheese
If I am selecting an item starting with B such as Bed, it would select the first time starting with B which would be Bad. This is if I only type the first two characters Be (did not test typing entire string as my real world case this would be unreasonable for a user to do so).
I have a ComboBox with the following settings:
AutoCompleteMode - SuggestAppend,
AutoCompleteSource - ListItems,
DropDownStyle - DropDownList.
To solve the problem I did the following as I noticed that my desired value was selected during the SelectedIndexChanged event but not the Leave event.
int myDesiredIndexSelection;
private void myComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
myDesiredIndexSelection = myComboBox.SelectedIndex;
}
private void myComboBox_Leave(object sender, EventArgs e)
{
myComboBox.SelectedIndex = myDesiredIndexSelection;
}
private void myForm_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Tab)
myComboBox.SelectedIndex = myDesiredIndexSelection;
}
The Leave event seems to address hitting the enter key. The KeyUp (KeyDown didn't work) seemed to fix the tab issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With