Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vb.net/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.NET WinForms组合框、相同项和SelectedIndexChanged事件_.net_Vb.net_Winforms - Fatal编程技术网

.NET WinForms组合框、相同项和SelectedIndexChanged事件

.NET WinForms组合框、相同项和SelectedIndexChanged事件,.net,vb.net,winforms,.net,Vb.net,Winforms,似乎当您有一个WinForms.NET应用程序和一个组合框(设置为“下拉”样式),并且组合框中有多个相同的项时,就会发生奇怪的事情。具体来说,所选项目的索引可以在不触发SelectedIndexChanged事件的情况下更改 当然,这会导致大量的混乱和奇怪的、模糊的错误,这就是我最近一直在做的事情 下面是一个简单的例子,你可以用它来了解我在说什么: 创建一个新的.NET WinForms项目(我使用VB.NET,但可以随意翻译-它足够简单) 将组合框、按钮和文本框(设置MultiLine=Tr

似乎当您有一个WinForms.NET应用程序和一个组合框(设置为“下拉”样式),并且组合框中有多个相同的项时,就会发生奇怪的事情。具体来说,所选项目的索引可以在不触发SelectedIndexChanged事件的情况下更改

当然,这会导致大量的混乱和奇怪的、模糊的错误,这就是我最近一直在做的事情

下面是一个简单的例子,你可以用它来了解我在说什么:

  • 创建一个新的.NET WinForms项目(我使用VB.NET,但可以随意翻译-它足够简单)
  • 将组合框、按钮和文本框(设置MultiLine=True)放到表单上
  • 使用以下代码加载包含3个相同项目的组合框,并在SelectedIndexChanged事件触发时打印一些状态消息,以及查看当前所选索引是什么(通过按钮):
运行项目并从组合框中选择一个项目(例如,中间的项目)。然后,单击组合框的下拉箭头,但不要选择任何内容。单击按钮(默认情况下为Button1)并查看其内容

除非我已经失去理智,否则以下是你应该看到的:

ComboBox SelectedIndexChanged event fired. SelectedIndex is: 1 Button clicked. SelectedIndex is: 0 ComboBox SelectedIndexChanged事件已激发。 所选索引为:1 点击按钮。 所选索引为:0 换句话说,所选索引已更改,但未触发SelectedIndexChanged事件

只有当组合框中的项目相同时,才会发生这种情况。如果他们不一样,这就不会发生。(如果组合框的“下拉”样式设置为“DropDownList”,也不会发生这种情况。)


我怀疑这可能是.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; } }
   }
}