8

这是一个简短的程序,可以重现我刚刚遇到的问题。这是在带有 .NET 4.0 的 MS Windows 7 下编译的,以防万一。

using System;
using System.Drawing;
using System.Windows.Forms;

// Compile with "csc /target:exe /out:comboboxbug.exe /r:System.dll /r:System.Drawing.dll /r:System.Windows.Forms.dll comboboxbug.cs"
// in a Visual Studio command prompt.

static class Program
{
    [STAThread]
    static void Main()
    {
        //Create a label.
        Label oLabel = new Label();
        oLabel.Location = new Point (10, 10);
        oLabel.Size = new Size (100, 15);
        oLabel.Text = "Combo box bug:";
        
        // Create a combo-box.
        ComboBox oComboBox = new ComboBox();
        oComboBox.Location = new Point (10, 50);
        oComboBox.Size = new Size (150, 21);
        oComboBox.Items.AddRange (new object[]
            { "A", "A B", "A C", "A B C", "A C B", "A B C D", "A C B D" });
        oComboBox.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
        oComboBox.AutoCompleteSource = AutoCompleteSource.ListItems;
        oComboBox.SelectionChangeCommitted
            += new EventHandler (comboBox_SelectionChangeCommitted);
        
        // Create a form.
        Form oForm = new Form();
        oForm.Size = new Size (200, 150);
        oForm.Controls.Add (oLabel);
        oForm.Controls.Add (oComboBox);
        
        // Run this form.
        Application.Run (oForm);
    }
    static void comboBox_SelectionChangeCommitted (object sender,
        EventArgs e)
    {
        MessageBox.Show ("SelectionChangeCommitted");
    }
}

单击组合框的文本部分并键入“A”。您将获得自动完成建议的列表。用鼠标单击其中一个选项。事件SelectionChangeCommitted不会发生!

选择一个菜单项而不使用自动完成。您将收到一个消息框,显示该SelectionChangeCommitted事件已发生!

鉴于在这两种情况下用户都更改了选择,在这两种情况下都不SelectionChangeCommitted应该调用吗?

使用SelectedIndexChanged事件不是一个选项,因为对于这个罐头示例背后的应用程序,我只希望它在用户进行选择时发生,而不是在以编程方式设置时发生。

编辑 2020 年 10 月 28 日:我发现了另一个SelectionChangeCommitted没有被调用的案例!甚至不需要为问题发生设置自动完成!单击以打开组合框,按与组合框项目之一的开头匹配的键,然后按 Tab 键离开。组合框项目被选中,但SelectionChangeCommitted未被调用!我修改后的答案如下。

4

5 回答 5

3

使用SelectedIndexChanged事件不是一个选项,因为对于这个罐头示例背后的应用程序,我只希望它在用户进行选择时发生,而不是在以编程方式设置时发生。

您还可以通过编写一个包装方法来更改暂时禁用您的事件的选择来完成此操作。

SelectionChangeCommitted不幸的是,对于更一般的情况(例如您无法控制ComboBox或访问它的方式),我不知道该问题的解决方案。

编辑:

我制作了 ComboBox 调用的所有事件的流媒体,并且似乎没有任何其他事件会满足您的需求。我能想到的唯一解决方案是挂钩自动完成触发的事件。困难在于知道这些事件是什么,因为它们似乎不会触发ComboBox我的小测试显示的内容。

于 2013-01-23T20:36:20.290 回答
1

仅供参考,这是我想出的最好的解决方案。显然,这是 ComboBox 子类上的 Leave 事件处理程序。SelectionChangeCommitted 事件不会在鼠标单击时发生,但至少会在 GUI 交互的正常流程中发生。

private void this_Leave (object sender, EventArgs e)
{
    // If this is an autocomplete combo-box, select the
    // item that was found by autocomplete.
    // This seems like something that ComboBox should be
    // doing automatically...I wonder why it doesn't?
    if (this.AutoCompleteMode != AutoCompleteMode.None)
    {
        // Determine which combo-box item matches the text.
        // Since IndexOf() is case-sensitive, do our own
        // search.
        int iIndex = -1;
        string strText = this.Text;
        ComboBox.ObjectCollection lstItems = this.Items;
        int iCount = lstItems.Count;
        for (int i = 0; i < iCount; ++i)
        {
            string strItem = lstItems[i].ToString();
            if (string.Compare (strText, strItem, true) == 0)
            {
                iIndex = i;
                break;
            }
        }

        // If there's a match, and this isn't already the
        // selected item, make it the selected item.
        //
        // Force a selection-change-committed event, since
        // the autocomplete was driven by the user.
        if (iIndex >= 0
        && this.SelectedIndex != iIndex)
        {
            this.SelectedIndex = iIndex;
            OnSelectionChangeCommitted (EventArgs.Empty);
        }
    }
}
于 2015-11-10T15:57:53.923 回答
0

这种解决方法对我来说很好,也希望对你有用。当通过在组合框中键入数据来使用自动完成以通过键盘或鼠标选择获取项目时,您需要 _KeyDown 事件。从内部调用 _SelectionChangeCommitted 方法,该方法包含其他操作的代码。请参见下面的代码:

    private void YourComboBox_KeyDown(object sender, KeyEventArgs e)
    {
        //Works also when user select and click on autocomplete list.
        if (e.KeyCode == Keys.Enter && YourComboBox.SelectedItem != null)
            YourComboBox_SelectionChangeCommitted(sender, e);
    }
于 2018-08-14T12:26:05.227 回答
0

对于上面提到的非自动完成案例(即我的 2020 年 10 月 28 日编辑),只要您的事件处理程序是idempotentLeave ,子类上的这个事件处理程序就会合并新案例和旧案例。与我之前的答案相比,它删除了自动完成的测试,并且总是调用.ComboBoxSelectionChangeCommittedOnSelectionChangeCommitted()

private void this_Leave (object sender, EventArgs e)
{
    // Determine which combo-box item matches the text.
    // Since IndexOf() is case-sensitive, do our own
    // search.
    int iIndex = -1;
    string strText = this.Text;
    ComboBox.ObjectCollection lstItems = this.Items;
    int iCount = lstItems.Count;
    for (int i = 0; i < iCount; ++i)
    {
        string strItem = lstItems[i].ToString();
        if (string.Compare (strText, strItem, true) == 0)
        {
            iIndex = i;
            break;
        }
    }

    // If there's a match, and this isn't already the
    // selected item, make it the selected item.
    if (iIndex >= 0
    && this.SelectedIndex != iIndex)
        this.SelectedIndex = iIndex;

    // Force a selection-change-committed event, since
    // the autocomplete was driven by the user.
    OnSelectionChangeCommitted (EventArgs.Empty);
}
于 2020-10-28T14:59:55.237 回答
0

如果有人遇到这个问题,我建议一个对我来说很好的解决方案......

跟我一起想想,要接受 Combo-box 的建议,一般用户需要用 Enter 键按下。

您可以写入组合框属性的 KeyDown 事件,如下所示:

    private void cboProperty_SelectionChangeCommitted(object sender, EventArgs e)
    {
       //Call here the event of SelectionChangeCommitted
       cboProperty_SelectionChangeCommitted(sender,null);
    }

它将在正确的时间引发 SelectionChangeCommitted。

于 2017-06-20T18:20:05.100 回答