.NET的WinForms组合框,相同的物品,和SelectedIndexChanged事件 [英] .NET WinForms ComboBox, identical items, and the SelectedIndexChanged event

查看:115
本文介绍了.NET的WinForms组合框,相同的物品,和SelectedIndexChanged事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

看来,当你有一个WinForms .NET应用程序一样,和一个ComboBox(设置为下拉的风格),以及组合框中有多个项目是相同的,奇怪的事情发生。具体地,所选择的项的索引可以改变的的击发SelectedIndexChanged事件。

当然,这将导致大规模的混乱和怪异的,模糊的错误,这正是我一直在拉我的头发在最近。<​​/ P>

下面是一个简单的例子,你可以用它来看看我说的:

  • 请一个新的.NET WinForms项目(我用VB.NET,但随时翻译 - 这是很简单的)。
  • 拖放一个组合框,一个按钮,和一个TextBox(设置的MultiLine =真)拖到窗体。
  • 使用以下code加载组合框与3相同的物品,并打印一些状态消息SelectedIndexChanged事件触发时,并查看当前选定的指标是(通过一个按钮):

 私人小组ComboBox1_SelectedIndexChanged(BYVAL发件人为System.Object的,BYVALË作为System.EventArgs)把手ComboBox1.SelectedIndexChanged
        TextBox1.Text = TextBox1.Text&vbNewLine和组合框SelectedIndexChanged事件被解雇。 &vbNewLine&_
            的SelectedIndex是:与ComboBox1.SelectedIndex
    结束小组

    私人小组Form1_Load的(BYVAL发件人为对象,BYVALË作为System.EventArgs)把手Me.Load
        ComboBox1.Items.Add(李四)
        ComboBox1.Items.Add(李四)
        ComboBox1.Items.Add(李四)

    结束小组

    私人小组的button1_Click(BYVAL发件人为System.Object的,BYVALË作为System.EventArgs)把手Button1.Click
        TextBox1.Text = TextBox1.Text&vbNewLine&_
        按钮点击。 &vbNewLine&_
        的SelectedIndex是:与ComboBox1.SelectedIndex
    结束小组 

运行该项目,并选择从ComboBox中的项目(比如,中间的一个)。然后,单击组合框的下拉箭头,但不要选择任何内容。点击按钮(Button1的默认情况下),看看它说。

除非我失去了我的脑海,这里是你应该看到:

 ComboBox的SelectedIndexChanged事件触发。
的SelectedIndex为:1
单击按钮。
的SelectedIndex为:0 

在换句话说,选定的索引发生了变化,但没有SelectedIndexChanged事件射击!

这仅发生在ComboBox中的项目是相同的。如果他们是不同的,这不会发生。 (它也不会发生,如果ComboBox中的下拉样式设置为DropDownList的。)

我怀疑这可能是在.NET框架本身就是一个错误,不是我可以修复,但在起飞的机会,任何人有什么在这里做的任何想法(或我可能是做错了!),请附和!我茫然地解释这种现象或解决它(我期望的SelectedIndex将保持不变,除非,你知道,你实际上改变它通过选择别的东西!)

解决方案

.NET框架实际上并不跟踪组合框的下拉列表中选定的指标;这是由Windows API的内部处理。作为此结果,.NET是依赖于Windows API来通知它当由发送到组合框的窗口句柄,以便它可以反过来触发SelectedIndexChanged事件通知消息的装置所选择的指数的变化。

不幸的是,事实证明,这.NET手表特定的通知消息( CBN_SELCHANGE 是精确的)并未涵盖所有可能的方案中选定的指数可能会改变。具体而言, CBN_SELCHANGE 仅由Windows API,如果用户点击,或选择使用箭头键,在下拉列表中的项目发送。然而,在下拉式的组合框,打开组合框的行为造成Windows来看看在组合框的编辑部分文本,通过搜索的匹配项的列表,如果发现匹配,自动选择匹配的项目(或第一个匹配的项目,如果有多个配套项目)。这可以改变选定的指数,但不发送 CBN_SELCHANGE 的通知消息,所以.NET错过它改变,不触发SelectedIndexChanged事件的事实。

Windows不会这一切都在一个下拉式的组合框,因为用户没有挑事在下拉列表;他们可以键入任何他们想要的。因此,每次打开组合框时它假设用户可能已经改变了文本,并试图用什么在列表中,如果它可以重新同步。

在你的情况,当你打开组合框第二次,它是重新同步并选择了第一场比赛在编辑部分的文字,这是李四#0和改变选择的索引0无.NET意识到。

因此​​,它基本上是在.NET Framework中的一个错误。不幸的是,没有完美的解决方法 - 你不能让Windows不做重新同步,并没有事件触发时再同步之后,在其中可以得到新选定的索引。 (下拉事件实际上触发重新同步发生权利之前,所以不会看到新的索引。)关于最好的,你可以做的是处理DropDownClosed事件,认为该指数可能会在这一点变化,并采取相应行动

It seems like when you have a WinForms .NET application, and a ComboBox (set to the "DropDown" style), and that ComboBox has multiple items in it that are identical, weird things happen. Specifically, the index of the selected item can change without firing the SelectedIndexChanged event.

Of course, this causes mass confusion and weird, obscure errors, which is what I've been pulling my hair out over lately.

Here's a simple example you can use to see what I'm talking about:

  • Make a new .NET WinForms project (I use VB.NET, but feel free to translate - it's simple enough).
  • Drop a ComboBox, a button, and a TextBox (set MultiLine=True) onto the form.
  • Use the following code to load the ComboBox with 3 identical items and to print some status messages when the SelectedIndexChanged event fires, and to see what the currently selected index is (via a button):

Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
        TextBox1.Text = TextBox1.Text & vbNewLine & "ComboBox SelectedIndexChanged event fired." & vbNewLine & _
            "SelectedIndex is: " & ComboBox1.SelectedIndex
    End Sub

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        ComboBox1.Items.Add("John Doe")
        ComboBox1.Items.Add("John Doe")
        ComboBox1.Items.Add("John Doe")

    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        TextBox1.Text = TextBox1.Text & vbNewLine & _
        "Button clicked." & vbNewLine & _
        "SelectedIndex is: " & ComboBox1.SelectedIndex
    End Sub

Run the project and select an item from the ComboBox (say, the middle one). Then, click the ComboBox's drop-down arrow, but DON'T SELECT ANYTHING. Click the Button (Button1 by default) and see what it says.

Unless I've lost my mind, here's what you should see:

ComboBox SelectedIndexChanged event fired.
SelectedIndex is: 1
Button clicked.
SelectedIndex is: 0

In other words, the SELECTED INDEX HAS CHANGED but without the SelectedIndexChanged event firing!

This only happens when the items in the ComboBox are identical. If they're different, this doesn't happen. (It also doesn't happen if the ComboBox's "DropDown" style is set to "DropDownList.")

I suspect this may be a bug in the .NET framework itself and not something I can fix, but on the off chance that anyone else has any ideas on what to do here (or what I might be doing wrong!), please chime in! I'm at a loss to explain this behavior or work around it (I expect the SelectedIndex to stay the same unless, y'know, you actually CHANGE it by selecting something else!)

解决方案

The .NET Framework does not actually keep track of the selected index of the combo box's drop down list; this is handled internally by the Windows API. As a consequence of this, .NET is reliant on the Windows API to notify it when the selected index changes by means of a notification message sent to the combo box's window handle, so that it can in turn fire the SelectedIndexChanged event.

Unfortunately, it turns out that the particular notification message that .NET watches for (CBN_SELCHANGE to be exact) does NOT cover all possible scenarios in which the selected index could change. Specifically, CBN_SELCHANGE is only sent by the Windows API if the user clicks on, or selects using the arrow keys, an item in the drop down list. However, in a DropDown style combo box, the act of opening the combo box causes Windows to look at the text in the edit portion of the combo box, search through the list of items for a match, and if a match is found, automatically select the matching item (or the first matching item, if there are multiple matching items). This can change the selected index, but does NOT send a CBN_SELCHANGE notification message, so .NET misses the fact that it changed and does not fire the SelectedIndexChanged event.

Windows does all this in a DropDown style combo box because the user does not HAVE to pick something in the drop down list; they can type whatever they want. So each time you open the combo box it assumes that the user might have changed the text and tries to re-sync with what's in the list if it can.

In your case, when you open the combo box for the second time, it is re-syncing and selecting the first match for the text in the edit portion, which is "John Doe" #0, and changing the selected index to 0 without .NET being aware.

So it basically is a bug in the .NET Framework. Unfortunately, there is no perfect workaround -- you can't get Windows to not do the re-sync, and there is no event that fires right after the re-sync occurs in which you can get the new selected index. (The DropDown event actually fires right before the re-sync occurs, so it will not see the new index.) About the best you can do is handle the DropDownClosed event, assume that the index might have changed at that point, and act accordingly.

这篇关于.NET的WinForms组合框,相同的物品,和SelectedIndexChanged事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆