Подтвердить что ты не робот

ComboBox.SelectedValue не соответствует отображаемому тексту, когда DropDownStyle = DropDownList в Windows 7

Скажем, у нас есть следующий код в приложении Windows:

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);

Здесь нет никакой магии, просто ComboBox привязан к списку строк. TextBox отображает SelectedValue ComboBox.

Я получаю неожиданное поведение при вводе "Bucket" в ComboBox и вкладке. По какой-то причине ComboBox отображает "Лодка", но TextBox отображает "Ведро". Я ожидаю, что оба они отобразят "Bucket" .

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

Еще интереснее то, что, набрав "Bucket" и уйдя, если я снова наберу "Bucket" , он отобразит "Bucket" в обоих. Если я сделаю третью попытку, она вернется к "Лодке" для ComboBox и "Bucket" для "TextBox". Так что кажется, что он едет на велосипеде через все B.

Я не заметил этого, пока не обновился с XP до Windows 7. Я не понимаю, как это может быть связано с этим, но я все равно отказываюсь.

Если это правильно, может ли кто-нибудь сказать мне, что я должен делать для достижения ожидаемого поведения?

UPDATE Казалось бы, это связано с Windows 7. Все работает так, как ожидалось, в режиме Windows XP. Может ли кто-нибудь еще запустить Windows 7 попробовать мой код и убедиться, что я не сумасшедший?

4b9b3361

Ответ 2

Обходной путь может изменить DropDownStyle на DropDown и добавить следующее:

comboBox.Validating += new CancelEventHandler((o, e) =>
    {
        e.Cancel = (comboBox.DataSource as string[]).Contains(comboBox.Text) == false;
    });

Это позволит пользователям вводить что-либо, но не позволяет им отходить от элемента управления, если только они не набрали действительный элемент.

Тем не менее, он не доволен изменением поведения с XP на Win 7.

Ответ 3

Я столкнулся с этим сам и нашел несколько обходных решений. В конце концов я применил собственное решение как подкласс ComboBox:

//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;
    }
  }
}

Ответ 4

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

Acorn Apple,
Bad
Кровать
Кирпич
Сыр

Если я выбираю элемент, начинающийся с B, например Bed, он выбирает первый раз, начиная с B, который был бы плохим. Это если я только набираю первые два символа Be (не тестировал типизацию всей строки в качестве моего реального мира, это было бы необоснованным для пользователя).

У меня есть ComboBox со следующими настройками:
Автозапуск - SuggestAppend,
Автозаполнение - ListItems,
DropDownStyle - DropDownList.

Чтобы решить проблему, я сделал следующее, поскольку заметил, что мое желаемое значение было выбрано во время события SelectedIndexChanged, но не событие Leave.

    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;
    }

Кажется, что событие "Оставить" касается нажатия клавиши ввода. KeyUp (KeyDown не работал), похоже, исправил проблему с вкладками.

Ответ 5

Я знаю, что этот ответ довольно старый, но мне нужно было ответить на эту ошибку Windows 7. Некоторое время я возился в духе Ecyrb и придумал следующую работу:

От InitForm() для приложения Добавьте это свойство:

Me.KeyPreview = True

Откуда находится ComboBox:

Private mbTab As Boolean 
Private miPrevIndex As Integer = -1
Private Sub DropDownListEx_Validating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles Me.Validating
   miPrevIndex = Me.SelectedIndex
   MyBase.OnSelectedIndexChanged(e)
End Sub
Private Sub DropDownListEx_PreviewKeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.PreviewKeyDownEventArgs) Handles Me.PreviewKeyDown
   mbTab = e.KeyCode = Windows.Forms.Keys.Tab
End Sub
Protected Overrides Sub OnDropDownClosed(ByVal e As System.EventArgs)
    MyBase.OnDropDownClosed(e)
    If Me.SelectedIndex <> miPrevIndex Then
        If mbTab = True Then
            Me.SelectedIndex = miPrevIndex
        Else
            miPrevIndex = Me.SelectedIndex
        End If
        MyBase.OnSelectedIndexChanged(e)
    End If
End Sub

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

Ответ 6

Переопределите метод OnTextChanged и просто не передавайте сообщение на базу.

protected override void OnTextChanged(EventArgs e)
{
    //Eat the message so it doesn't select an incorrect value.
}

Ответ 7

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

Private Sub LeaveComboBox(s As Object, e As EventArgs) Handles ComboBox1.Leave
    Dim sender as ComboBox = DirectCast(s, ComboBox)

    If sender.DroppedDown Then
        ' Save the correct item
        Dim correctSelection as Object = sender.SelectedItem

        ' The core of the issue seems to be that while searching, Leave is
        ' triggered before DropDownClosed when you hit the TAB.
        ' Instead, trigger that now:
        sender.DroppedDown = False

        ' Restore the correct item.
        sender.SelectedItem = correctSelection
    End If
End Sub