ComboBox.SelectedValue не соответствует отображаемому тексту, когда DropDownStyle = DropDownList в Windows 7 - PullRequest
12 голосов
/ 04 января 2010

Допустим, у нас есть следующий код в приложении 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 отображает «Ведро». Я ожидал бы, что они оба покажут «Ведро».

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

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

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

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

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

Ответы [ 7 ]

6 голосов
/ 04 января 2010

В качестве обходного пути можно изменить DropDownStyle на DropDown и добавить следующее:

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

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

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

2 голосов
/ 14 августа 2013

Это исправление решит эту проблему.

1 голос
/ 06 мая 2017

Я все еще могу воспроизвести это в 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
1 голос
/ 11 ноября 2014

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

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

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

У меня есть ComboBox со следующими настройками:
AutoCompleteMode - SuggestAppend,
AutoCompleteSource - 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;
    }

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

1 голос
/ 23 марта 2012

Я сам столкнулся с этим и нашел несколько обходных путей. В конце концов я выбрал собственное решение в качестве подкласса 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;
    }
  }
}
0 голосов
/ 14 февраля 2012

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

protected override void OnTextChanged(EventArgs e)
{
    //Eat the message so it doesn't select an incorrect value.
}
0 голосов
/ 12 августа 2010

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

Из 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. Поэтому вам нужно будет подключить их для собственного использования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...