.NET WinForms组合框、相同项和SelectedIndexChanged事件
似乎当您有一个WinForms.NET应用程序和一个组合框(设置为“下拉”样式),并且组合框中有多个相同的项时,就会发生奇怪的事情。具体来说,所选项目的索引可以在不触发SelectedIndexChanged事件的情况下更改 当然,这会导致大量的混乱和奇怪的、模糊的错误,这就是我最近一直在做的事情 下面是一个简单的例子,你可以用它来了解我在说什么:.NET WinForms组合框、相同项和SelectedIndexChanged事件,.net,vb.net,winforms,.net,Vb.net,Winforms,似乎当您有一个WinForms.NET应用程序和一个组合框(设置为“下拉”样式),并且组合框中有多个相同的项时,就会发生奇怪的事情。具体来说,所选项目的索引可以在不触发SelectedIndexChanged事件的情况下更改 当然,这会导致大量的混乱和奇怪的、模糊的错误,这就是我最近一直在做的事情 下面是一个简单的例子,你可以用它来了解我在说什么: 创建一个新的.NET WinForms项目(我使用VB.NET,但可以随意翻译-它足够简单) 将组合框、按钮和文本框(设置MultiLine=Tr
- 创建一个新的.NET WinForms项目(我使用VB.NET,但可以随意翻译-它足够简单)
- 将组合框、按钮和文本框(设置MultiLine=True)放到表单上
- 使用以下代码加载包含3个相同项目的组合框,并在SelectedIndexChanged事件触发时打印一些状态消息,以及查看当前所选索引是什么(通过按钮):
我怀疑这可能是.NET framework本身的一个bug,我无法修复它,但如果其他人对此有任何想法(或者我可能做错了什么!),请插话!我无法解释这一行为或解决它(我希望SelectedIndex保持不变,除非,你知道,你实际上通过选择其他内容来更改它!)NET Framework实际上没有跟踪组合框下拉列表中选定的索引;这是由Windows API在内部处理的。因此,.NET依赖Windows API,通过发送到组合框窗口句柄的通知消息,在所选索引更改时通知它,以便它可以依次触发SelectedIndexChanged事件 不幸的是,.NET监视的特定通知消息(
CBN_SELCHANGE
确切地说)并没有涵盖所选索引可能更改的所有可能情况。具体而言,CBN\u SELCHANGE
仅在用户单击或使用箭头键选择下拉列表中的项目时由Windows API发送。但是,在下拉式组合框中,打开组合框的操作会使Windows查看组合框编辑部分的文本,在项目列表中搜索匹配项,如果找到匹配项,则自动选择匹配项(如果有多个匹配项,则选择第一个匹配项)。这可以更改所选索引,但不会发送CBN\u SELCHANGE
通知消息,因此.NET会忽略它已更改的事实,并且不会触发SelectedIndexChanged事件
Windows在下拉式组合框中执行所有这些操作,因为用户不必在下拉列表中选择某些内容;他们可以随心所欲地打字。因此,每次打开组合框时,它都假设用户可能已更改文本,并尝试与列表中的内容重新同步(如果可以)
在您的情况下,当您第二次打开组合框时,它将重新同步并为编辑部分中的文本选择第一个匹配项,即“John Doe”#0,并在.NET不知道的情况下将所选索引更改为0
所以它基本上是.NET框架中的一个bug。不幸的是,没有完美的解决方法——您无法让Windows不执行重新同步,也没有在重新同步发生后立即触发的事件可以获取新的选定索引。(DropDown事件实际上是在重新同步发生之前触发的,因此它不会看到新的索引。)您所能做的最好的事情就是处理DropDownClosed事件,假设索引可能在那一点上发生了更改,并采取相应的行动。Eric的回答非常彻底,但我惊讶地看到它没有以“…但实际上,您应该问问自己,为什么要用重复的项填充组合框。”毫无疑问,.Net framework错误是允许存在的,因为当您按预期使用控件时,为了允许用户从列表中选择项,您不会遇到此错误 用户将如何区分相同的条目?为什么他们会选择一个而不是另一个?不同的条目有不同的含义吗?如果有,那么重复条目是不明确的,这总是不好的可用性设计。如果没有,那么你不应该有重复的条目 我能想到的唯一有意义的场景是,当您有一个由多组相关项组成的大列表时,其中一个或多个项逻辑上适合多个组,因此您希望在两个部分中显示它
我猜你的设计没有考虑到这样一个事实,即可能有多个相同的条目,并且这个省略会产生比这个问题更重要的其他可用性影响。当然,我理解你可能正在做一些我没有想到的事情,在哪些方面做你正在做的事情完全有意义,在哪些方面你可以随意忽略我的评论。 在列表中重复项目不仅是有效的,而且是可取的。考虑当你按下打开的文件按钮时,在VisualStudio中看到的OpenFieldLabor组合框。这显示了一个组合框,里面有“我的计算机”、“桌面”之类的条目。 ComboBox SelectedIndexChanged event fired. SelectedIndex is: 1 Button clicked. SelectedIndex is: 0
C:\
C:\A
C:\A\B
C:\A\B\A
C:\
A
B
A
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace ComboBoxTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
if (DesignMode)
return;
BindingList<CBItem> items = new BindingList<CBItem>();
items.Add(new CBItem("A", @"C:\A"));
items.Add(new CBItem("B", @"C:\A\B"));
items.Add(new CBItem("A", @"C:\A\B\A"));
comboBox.DisplayMember = "DisplayValue";
comboBox.ValueMember = "RealValue";
comboBox.DataSource = items;
comboBox.SelectedValue = @"C:\A\B\A";
}
}
class CBItem
{
public CBItem(string displayValue, string realValue)
{
_displayValue = displayValue;
_realValue = realValue;
}
private readonly string _displayValue, _realValue;
public string DisplayValue { get { return _displayValue; } }
public string RealValue { get { return _realValue; } }
}
}