WinForms ComboBox SelectedIndexChanged не срабатывает при наборе нескольких символов, а затем Alt + Down - PullRequest
13 голосов
/ 21 января 2011

Короче

Когда я набираю символ в ComboBox, нажимаю Alt + Down, а затем Enter или Tab, событие SelectedIndexChanged не срабатывает, даже если значение SelectedIndex действительно меняется! Почему не происходит событие?

Обновление Та же ошибка возникает, если вы вводите символ, нажимаете Alt + Down и затем нажимаете Esc. Вы ожидаете, что Esc отменит изменения. Однако SelectedIndex меняет , а событие SelectedIndexChanged не срабатывает.

Что должно произойти, если вы просто наберете Alt + Down, с помощью клавиш со стрелками перейдите к записи, а затем наберите Esc? Должен ли выбранный индекс быть возвращен к его первоначальному значению?


Не так коротко

У меня есть приложение WinForm с ComboBox. Событие SelectedIndexChanged ComboBox связано с обработчиком событий, который показывает SelectedItem в элементе управления Label. Коллекция ComboBox 'Items имеет три значения: «Один», «Два» и «Три».

  • Когда я выбираю элемент мышью, происходит событие.
  • Когда я прокручиваю мышь, происходит событие.
  • Когда я использую Alt + Down, чтобы развернуть комбинированный список и пройтись по пунктам вверх и вниз, событие запускается.
  • Но ... Когда я набираю первый символ значения, , затем , нажмите Alt + Down, затем Enter или Tab, значение выбирается и отображается в выпадающем списке, но событие не срабатывает.

Я также добавил кнопку, которая показывает SelectedIndex. Он показывает, что SelectedIndex изменилось . Поэтому, хотя SelectedIndex действительно изменяется, событие SelectedIndexChanged не срабатывает!

Если я просто введу правильное значение, такое как One , событие также не сработает, но в этом случае нажатие кнопки показывает, что SelectedIndex действительно не изменился. Так что в этом случае поведение нормальное.


Для воспроизведения создайте Форму и добавьте ComboBox, Метку и Кнопку. Поместите следующий код в Form1.cs:

using System;
using System.Windows.Forms;

namespace ComboBoxSelectedIndexChanged
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            comboBox1.Items.AddRange(new object[] {
                "One",
                "Two",
                "Three"
            });
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            label1.Text = "Selected index: " + comboBox1.SelectedIndex;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Selected item: " + comboBox1.SelectedItem +
                "\nSelected index: " + comboBox1.SelectedIndex);
        }
    }
}

Ответы [ 5 ]

6 голосов
/ 21 января 2011

Я пробовал несколько поисков в Google, чтобы найти однозначный ответ на этот вопрос, но раньше его не нашел.Только сейчас я нашел ветку, которая фактически ссылается на статью базы знаний Microsoft о проблеме.Статья KB948869 описывает проблему.

В статье базы знаний предлагается создать свой собственный комбинированный список и переопределить метод ProcessDialogKey.

using System.Windows.Forms;

public class MyComboBox : ComboBox
{
    protected override bool ProcessDialogKey(Keys keyData)
    {
        if (keyData == Keys.Tab)
            this.DroppedDown = false;
        return base.ProcessDialogKey(keyData);
    }
}

Я пробовал, нок сожалению, это, кажется, не имеет никакого эффекта.Что немного странно.Я ожидаю, что обходной путь, описанный в статье базы знаний, будет точным.

Однако я нашел другой обходной путь, который заключается в использовании вместо него события DropDownClosed.

private void comboBox1_DropDownClosed(object sender, EventArgs e)
{
    label1.Text = "DroDownClosed Selected index: " + comboBox1.SelectedIndex;
}

This похоже работает, но только при использовании DropDownStyle.DropDown.Когда вы устанавливаете DropDownStyle в DropDownList, при вводе символа не запускается DropDownClosed (поскольку в этом случае в действительности нет выпадающего списка).Только если вы действительно откроете выпадающий список и выберете значение, вызывается событие DropDownClosed.

Таким образом, оба варианта на самом деле не являются хорошим ответом.

Обновление Я даже пытался переопределить свойство SelectedIndex в MyComboBox, вызвав его OnSelectedIndexChanged(EventArgs.Empty).После ввода символа и нажатия Alt + Down запускается установщик, но он устанавливает значение -1, которое уже есть.После нажатия клавиши Tab установщик больше не выполняется, хотя каким-то образом значение SelectedIndex меняет .Похоже, что ComboBox напрямую меняет поле поддержки для SelectedIndex, минуя настройки.Я полагаю, что что-то подобное может происходить и в реальном ComboBox.

5 голосов
/ 21 января 2011

Соответствующее значение свойства DropDown здесь - DropDownList. У него нет этой проблемы.

Найти обходной путь для вашей конкретной проблемы со стилем DropDown, установленным на DropDown, довольно сложно. Это позволяет пользователю вводить произвольный текст, и даже идеальное совпадение с одним из выпадающих элементов не меняет SelectedIndex. Вы должны реализовать событие Validating и найти совпадение самостоятельно. Событие DropDownClosed подойдет для вашего конкретного сценария. Но на самом деле, всегда используйте DropDownList, если вы хотите идеальные совпадения.

2 голосов
/ 16 августа 2012

У меня была проблема ESC в выпадающем списке в стиле DropDownList.Я немного изменил то, что сработало для меня, чтобы удовлетворить ваши потребности:

public class MyComboBox : System.Windows.Forms.ComboBox
{
  private bool _sendSic;

  protected override void OnPreviewKeyDown(System.Windows.Forms.PreviewKeyDownEventArgs e)
  {
    base.OnPreviewKeyDown(e);

    if (DroppedDown)
    {
      switch(e.KeyCode)
      {
        case System.Windows.Forms.Keys.Escape:
          _sendSic = true;
          break;
        case System.Windows.Forms.Keys.Tab:
        case System.Windows.Forms.Keys.Enter:
          if(DropDownStyle == System.Windows.Forms.ComboBoxStyle.DropDown)
            _sendSic = true;
          break;
      }
    }
  }

  protected override void OnDropDownClosed(System.EventArgs e)
  {
    base.OnDropDownClosed(e);

    if(_sendSic)
    {
      _sendSic = false;
      OnSelectedIndexChanged(System.EventArgs.Empty);
    }
  }
}

Для этого нужно слушать нажатия клавиш, которые появляются, когда раскрывающийся список открыт.Если это ESC , TAB или ENTER для DropDown стиля ComboBox или ESC для DropDownList стиля ComboBox,SelectedIndexChanged - Событие запускается при закрытии DropDown.Я никогда не использовал ComboBoxStyle.Simple и не знаю, как это работает или должно работать, но поскольку, насколько мне известно, никогда не отображает DropDown, это должно быть безопасно даже для этого стиля.

Если вы не хотите наследовать от ComboBox для создания собственного элемента управления, вы также можете применить аналогичную логику к ComboBox в форме, подписавшись на его события PreviewKeyDown и DropDownClosed.

2 голосов
/ 22 января 2011

Поправь меня, если я ошибаюсь.Вот код, который я использовал.

comboBox1.Items.AddRange(new object[] {
                "One",
                "Two",
                "Three"
});

comboBox1.SelectedIndexChanged+=(sa,ea)=>
 {
   label1.Text = "Selected index: " + comboBox1.SelectedIndex;
 };
comboBox1.TextChanged+= (sa, ea) =>
 {
 comboBox1.SelectedIndex = comboBox1.FindStringExact(comboBox1.Text);

 //OR
 //comboBox1.SelectedIndex = comboBox1.Items.IndexOf(comboBox1.Text);
  comboBox1.SelectionStart  = comboBox1.Text.Length;
};
1 голос
/ 22 мая 2013

Я получил свой собственный класс из ComboBox:

public class EditableComboBox : ComboBox
{
    protected int backupIndex;
    protected string backupText;

    protected override void OnDropDown(EventArgs e)
    {
        backupIndex = this.SelectedIndex;
        if (backupIndex == -1) backupText = this.Text;
        else backupText = null;
        base.OnDropDown(e);
    }

    protected override void OnSelectionChangeCommitted(EventArgs e)
    {
        backupIndex = -2;
        base.OnSelectionChangeCommitted(e);
    }

    protected override void OnSelectionIndexChanged(EventArgs e)
    {
        backupIndex = -2;
        base.OnSelectionIndexChanged(e);
    }

    protected override void OnDropDownClosed(EventArgs e)
    {
        if (backupIndex > -2 && this.SelectedIndex != backupIndex)
        {
            if (backupIndex > -1)
            {
                this.SelectedIndex = backupIndex;
            }
            else
            {
                string oldText = backupText;
                this.SelectedIndex = -1;
                this.Text = oldText;
                this.SelectAll();
            }
        }
        base.OnDropDownClosed(e);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...