Prevent bypassing SelectedIndexChanged in ComboBox

721 views Asked by At

I was surprised, that SelectedIndexChanged on a ComboBox with ComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList can be bypassed by changing the shown value to another one.

Here are steps to reproduce the case:

  • Create a Form with a ComboBox with ComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownListand some other control, which can get the focus (e.g. TextBox)
  • Attach an event handler for ComboBox.SelectedIndexChanged and let say do reset the selected index of ComboBox there always to 0 for only first entry could be selected.
  • Fill ComboBox.Items with e.g. integers from 1 to 5.
  • Start the application and open drop down list
  • Click any entry except the first and hold left mouse button down(no LMBUp must be triggered)
  • Press TAB key holding the left mouse button down
  • Clicked value is shown in the ComboBox and no ComboBox.SelectedIndexChanged being triggered.

What would be your offer to prevent this undesirable behavior. Tab key must not be suppressed and ComboBox.SelectedIndexChanged must be triggered on change.

Some code for copy-paste:

public Form1()
{
    InitializeComponent();

    comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
    comboBox1.Items.Add(1);
    comboBox1.Items.Add(2);
    comboBox1.Items.Add(3);
    comboBox1.Items.Add(4);
    comboBox1.Items.Add(5);
    
    comboBox1.SelectedIndexChanged += ComboBox1_SelectedIndexChanged;
}
private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    comboBox1.SelectedIndex = 0;
}
2

There are 2 answers

0
Rekshino On BEST ANSWER

I have solved it with derived control:

class ModifiedComboBox : ComboBox
{
    private object _lastSelectedItem = null;

    protected override void OnDropDownClosed(EventArgs e)
    {
        if(SelectedItem != _lastSelectedItem)
        {
            OnSelectedIndexChanged(new EventArgs());
        }
        base.OnDropDownClosed(e);
    }

    protected override void OnSelectedIndexChanged(EventArgs e)
    {
        _lastSelectedItem = SelectedItem;
        base.OnSelectedIndexChanged(e);
    }
}
9
JohnG On

It is unclear “why” you want this odd behavior from a ComboBox; however, it appears you did not look a little closer at the ComboBox events.

It is true what you describe... When the user presses the Tab key “while” still holding the mouse button on a selection in the combo box… then the ComboBoxes SelectedIndexChanged event does NOT fire since the control is still IN the process of “selecting” a different index.

However, the ComboBoxes Validating and Leave events DO fire in the above situation. Instead of creating another control for this, wiring up the combo boxes Validating or Leave event will fix what you describe. Something like…

The current SelectedIndexChanged for normal situations…

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) {
  comboBox1.SelectedIndexChanged -= new System.EventHandler(comboBox1_SelectedIndexChanged);
  comboBox1.SelectedIndex = 0;
  comboBox1.SelectedIndexChanged += new System.EventHandler(comboBox1_SelectedIndexChanged);
}

Then, using the ComboBoxes Leave event for the “special” case when the user Tabs out of the combo box.

private void comboBox1_Leave(object sender, EventArgs e) {
  comboBox1.SelectedIndexChanged -= new System.EventHandler(comboBox1_SelectedIndexChanged);
  comboBox1.SelectedIndex = 0;
  comboBox1.SelectedIndexChanged += new System.EventHandler(comboBox1_SelectedIndexChanged);
}