在 Windows 7 中 DropDownStyle = DropDownList 时,ComboBox.SelectedValue 与显示的文本不匹配
Posted
技术标签:
【中文标题】在 Windows 7 中 DropDownStyle = DropDownList 时,ComboBox.SelectedValue 与显示的文本不匹配【英文标题】:ComboBox.SelectedValue does not match displayed text when DropDownStyle = DropDownList in Windows 7 【发布时间】:2011-01-01 08:42:29 【问题描述】:假设我们在 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
显示ComboBox
的SelectedValue
。
当我在 ComboBox
中键入“Bucket”并离开时,我遇到了意外行为。出于某种原因,ComboBox
显示“Boat”,但TextBox
显示“Bucket”。我希望他们都显示“桶”。
如果我将DropDownStyle
更改为DropDown
,它会按预期运行,但我不希望用户能够输入他们想要的任何内容。他们应该只能键入列表中的项目。
更有趣的是,在键入“Bucket”并跳开后,如果我再次键入“Bucket”,它会在两者中显示“Bucket”。如果我进行第三次尝试,它会返回到 ComboBox
的“Boat”和“TextBox”的“Bucket”。所以它似乎在所有 B 中循环。
直到我最近从 XP 升级到 Windows 7 时才注意到这一点。我不明白这与这有什么关系,但我还是把它扔掉了。
如果这种行为是正确的,谁能告诉我应该做些什么来实现我的预期行为?
更新这似乎与 Windows 7 相关。在 Windows XP 模式下,一切都按预期运行。其他运行 Windows 7 的人可以尝试我的代码并验证我没有发疯吗?
【问题讨论】:
我完全采用了您的代码并将其扔到一个新的表单上,并且无法重现该行为。您可能会尝试连接 SelectedIndexChanged 事件并在其中输入一些控制台消息,然后在您键入组合时查看发生了什么。 我添加了comboBox.SelectedIndexChanged += new EventHandler(delegate Console.WriteLine("SelectedIndex = 0", comboBox.SelectedIndex); );
,输出显示SelectedIndex
更改为“2”,然后更改为“3”,这与TextBox
显示的内容相匹配。
如果这是一个可重现的错误,您应该将其提交给 Microsoft Connect:connect.microsoft.com/VisualStudio
我希望其他运行 Win7 的人可以先确认一下,但我已经继续并打开了一个错误:connect.microsoft.com/VisualStudio/feedback/…。
我刚刚尝试过,我也可以复制(尽管我没有尝试查看它是否可以在 XP 上复制)。我已对您的 Connect 错误表示赞成并声明我可以复制它。这个问题现在可以结束了。
【参考方案1】:
解决方法可能是将DropDownStyle
更改为DropDown
并添加以下内容:
comboBox.Validating += new CancelEventHandler((o, e) =>
e.Cancel = (comboBox.DataSource as string[]).Contains(comboBox.Text) == false;
);
这将允许用户键入任何内容,但除非他们键入有效项,否则不会让他们离开控件。
仍然对从 XP 到 Win 7 的行为变化不满意。
【讨论】:
+1 这是适合我的 vb.net 版本:e.Cancel = Not (comboBox.Items.Contains(comboBox.Text))
。【参考方案2】:
我知道这个回复已经很老了,但我需要一个关于这个 Windows 7 错误的答案。我在 Ecyrb 的脉络中修补了一段时间,并想出了以下解决方法:
从 InitForm() 为 Application 添加此属性:
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
现在,在我的示例中,我使用的是继承组合框的自定义控件。因此,您需要将它们连接起来以供自己使用。
【讨论】:
【参考方案3】:覆盖OnTextChanged
方法,只是不要将消息传递到基层。
protected override void OnTextChanged(EventArgs e)
//Eat the message so it doesn't select an incorrect value.
【讨论】:
【参考方案4】:我自己遇到了这个问题,并找到了一些解决方法。最后,我将自己的解决方案作为 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;
【讨论】:
【参考方案5】:这个hotfix 将解决这个问题。
【讨论】:
虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。 嗯,这是微软发布的修补程序下载页面的链接。这里没有什么要补充的,我不希望这个链接过期:)【参考方案6】:我创建了自己的解决方案,因为我不认为将修补程序部署到所有用户计算机是合理或可管理的。但是修补程序问题描述描述了我的问题。例如,请参见下面的列表:
橡子 苹果 不好 床 砖 奶酪
如果我选择以 B 开头的项目,例如床,它会选择第一次以 B 开头的,这将是错误的。这是如果我只输入前两个字符 Be(没有测试输入整个字符串作为我的真实情况,这对用户来说是不合理的)。
我有一个具有以下设置的 ComboBox:AutoCompleteMode - SuggestAppend、AutoCompleteSource - ListItems、DropDownStyle - 下拉列表。
为了解决这个问题,我注意到在 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 不起作用)似乎解决了选项卡问题。
【讨论】:
【参考方案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
【讨论】:
以上是关于在 Windows 7 中 DropDownStyle = DropDownList 时,ComboBox.SelectedValue 与显示的文本不匹配的主要内容,如果未能解决你的问题,请参考以下文章
您如何在 Windows 中注册最近使用列表以准备 Windows 7?