.net 在Windows 7中,当DropDownStyle=DropDownList时,ComboBox.SelectedValue与显示的文本不匹配

.net 在Windows 7中,当DropDownStyle=DropDownList时,ComboBox.SelectedValue与显示的文本不匹配,.net,winforms,data-binding,windows-7,combobox,.net,Winforms,Data Binding,Windows 7,Combobox,假设Windows应用程序中有以下代码: ComboBox comboBox = new ComboBox() { AutoCompleteMode = AutoCompleteMode.SuggestAppend, AutoCompleteSource = AutoCompleteSource.ListItems, DataSource = new string[] { "", "Ark", "Boat", "Bucket" }, DropDownStyle =

假设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);
这里没有魔法,只有一个绑定到字符串列表的组合框。
文本框
显示组合框的
SelectedValue

当我在
组合框中键入“Bucket”并将其制表时,出现了意外行为。由于某种原因,
组合框
显示“Boat”,而
文本框
显示“Bucket”。我希望它们都显示“Bucket”

如果我将
DropDownStyle
更改为
DropDownStyle
,它的行为与预期一样,但我不希望用户能够键入他们想要的任何内容。他们应该只能键入列表中的项目

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
更有趣的是,在输入“Bucket”并切换到其他位置后,如果我再次输入“Bucket”,它将在这两个位置显示“Bucket”。如果我第三次尝试,它会返回到
组合框的“Boat”和'TextBox'的“Bucket”。所以它似乎在所有的B中循环

直到最近我从XP升级到Windows7,我才注意到这一点。我不明白这和这有什么关系,但我还是要把它扔掉

如果这种行为是正确的,有人能告诉我应该做什么来实现我的预期行为吗


更新这似乎与Windows 7有关。在Windows XP模式下,一切正常。运行Windows 7的其他人是否可以尝试我的代码并验证我是否疯了?

一种解决方法可能是将
下拉样式更改为
下拉样式,并添加以下内容:

comboBox.Validating += new CancelEventHandler((o, e) =>
    {
        e.Cancel = (comboBox.DataSource as string[]).Contains(comboBox.Text) == false;
    });
这将允许用户键入任何内容,但除非他们键入了有效的项,否则不会让他们离开控件


尽管如此,我还是对从XP到Win 7的行为不满意。

我知道这个响应很老,但我需要一个Windows 7错误的答案。我在Ecyrb的脉络中进行了一段时间的修补,并提出了以下解决方案:

从应用程序的InitForm()添加此属性:

Me.KeyPreview = True
从组合框所在的位置:

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
Private mbTab作为布尔值
私有miPrevIndex为整数=-1
私有子DropDownListEx_验证(ByVal发送方作为对象,ByVal e作为System.ComponentModel.CancelEventArgs)处理我。验证
miPrevIndex=Me.SelectedIndex
MyBase.OnSelectedIndexChanged(e)
端接头
私有子DropDownlineStex_PreviewKeyDown(ByVal发件人作为对象,ByVal e作为System.Windows.Forms.PreviewKeyDownEventArgs)处理我。PreviewKeyDown
mbTab=e.KeyCode=Windows.Forms.Keys.Tab
端接头
受保护的覆盖子OnDropDownClosed(通过值e作为System.EventArgs)
MyBase.OnDropDownClosed(e)
如果Me.SelectedIndex mipreIndex,则
如果mbTab=True,则
Me.SelectedIndex=mipreIndex
其他的
miPrevIndex=Me.SelectedIndex
如果结束
MyBase.OnSelectedIndexChanged(e)
如果结束
端接头

现在,在我的示例中,我使用了一个继承comboBox的自定义控件。因此,您需要将这些连接起来以供自己使用。

覆盖
OnTextChanged
方法,只是不要将消息传递给基底

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

我自己也遇到了这个问题,找到了一些解决办法。最后,我将自己的解决方案作为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;
    }
  }
}

这将解决这个问题。

我创建了自己的解决方案,因为我不认为向所有用户和计算机部署修补程序是合理的或可管理的。但是,修补程序问题描述描述了我的问题。例如,请参见下面的列表:

橡子 苹果
坏的

砖块
奶酪

如果我选择一个以B开头的项目,例如Bed,它将选择第一次以B开头,这将是不好的。这是如果我只键入前两个字符Be(没有像我的实际情况那样测试键入整个字符串,这对于用户来说是不合理的)

我有一个具有以下设置的组合框:
自动完成模式-SuggestAppend,
自动完成源-列表项,
下拉样式-下拉列表

为了解决这个问题,我做了以下操作,因为我注意到在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事件似乎解决了按enter键的问题。KeyUp(KeyDown不起作用)似乎解决了选项卡问题。

我仍然可以在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

我准确地获取了您的代码,并以新的形式将其丢弃,因此无法复制该行为。您可以尝试连接SelectedIndexChanged事件,并在其中抛出一些控制台消息,然后查看在键入组合时发生的情况。我添加了
comboBox.SelectedIndexChanged+=new EventHandler(委托{console.WriteLine(“SelectedIndex={0}”,comboBox.SelectedIndex);})输出显示,
SelectedIndex
变为“2”,然后变为“3”,这与
TextBox
显示的内容相匹配。如果这是一个可复制的错误,您应该将其提交给Microsoft Connect:我希望运行Win7的其他人可以首先确认,但我已经打开了一个bug:。我只是尝试了一下,我也可以重新编程(尽管我还没有尝试查看它是否在XP上重新编程)。我已经升级了你的连接错误,并声明我可以重新设置它。此问题现在可以关闭。虽然此链接可以回答此问题,但最好在此处包含答案的基本部分,并提供链接以供参考。如果链接页面发生更改,只有链接的答案可能会无效。这是指向Microsoft提供的修补程序下载页面的链接。这里没有什么可添加的,我也不希望这个链接过期:)+1这是对我有效的vb.net版本:
e.Cancel=not(comboBox.Items.Contains(comboBox.Text))