【问题标题】:Prevent bypassing SelectedIndexChanged in ComboBox防止绕过 ComboBox 中的 SelectedIndexChanged
【发布时间】:2021-08-25 17:50:37
【问题描述】:

我很惊讶,ComboBoxComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList 上的 SelectedIndexChanged 可以通过将显示的值更改为另一个值来绕过。

以下是重现案例的步骤:

  • 创建FormComboBoxComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList 以及其他一些可以获得焦点的控件(例如TextBox
  • ComboBox.SelectedIndexChanged 附加一个事件处理程序并让 说不要将ComboBox的选定索引重置为0 只能选择第一个条目。
  • 填写ComboBox.Items,例如从 1 到 5 的整数。
  • 启动应用程序并打开下拉列表
  • 单击除第一个以外的任何条目并按住鼠标左键(无 LMBUp 必须触发)
  • 按住鼠标左键按下TAB
  • 点击值显示在ComboBox中,没有 ComboBox.SelectedIndexChanged 被触发。

您会提出什么建议来防止这种不良行为。 Tab 键不得被抑制,ComboBox.SelectedIndexChanged 必须在更改时触发。

复制粘贴的一些代码:

public Form1()
{
    InitializeComponent();

    comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
    comboBox1.Items.Add(1);
    comboBox1.Items.Add(2);
    comboBox1.Items.Add(3);
    comboBox1.Items.Add(4);
    comboBox1.Items.Add(5);
    
    comboBox1.SelectedIndexChanged += ComboBox1_SelectedIndexChanged;
}
private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    comboBox1.SelectedIndex = 0;
}

【问题讨论】:

标签: c# winforms combobox event-handling selectedindexchanged


【解决方案1】:

我已经用派生控制解决了:

class ModifiedComboBox : ComboBox
{
    private object _lastSelectedItem = null;

    protected override void OnDropDownClosed(EventArgs e)
    {
        if(SelectedItem != _lastSelectedItem)
        {
            OnSelectedIndexChanged(new EventArgs());
        }
        base.OnDropDownClosed(e);
    }

    protected override void OnSelectedIndexChanged(EventArgs e)
    {
        _lastSelectedItem = SelectedItem;
        base.OnSelectedIndexChanged(e);
    }
}

【讨论】:

    【解决方案2】:

    不清楚“为什么”你想要 ComboBox 的这种奇怪行为;但是,您似乎没有仔细观察ComboBox 事件。

    你所描述的是真的......当用户按下 Tab 键“同时”仍然在组合框中的选择上按住鼠标按钮......然后 ComboBoxes SelectedIndexChanged 事件不会触发,因为控件仍在“选择”不同索引的过程中。

    但是,ComboBoxes ValidatingLeave 事件在上述情况下会触发。无需为此创建另一个控件,而是连接组合框 ValidatingLeave 事件将修复您所描述的内容。像……

    正常情况下的当前SelectedIndexChanged...

    private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) {
      comboBox1.SelectedIndexChanged -= new System.EventHandler(comboBox1_SelectedIndexChanged);
      comboBox1.SelectedIndex = 0;
      comboBox1.SelectedIndexChanged += new System.EventHandler(comboBox1_SelectedIndexChanged);
    }
    

    然后,使用ComboBoxesLeave 事件来处理当用户跳出组合框时的“特殊”情况。

    private void comboBox1_Leave(object sender, EventArgs e) {
      comboBox1.SelectedIndexChanged -= new System.EventHandler(comboBox1_SelectedIndexChanged);
      comboBox1.SelectedIndex = 0;
      comboBox1.SelectedIndexChanged += new System.EventHandler(comboBox1_SelectedIndexChanged);
    }
    

    【讨论】:

    • 您是指“组合框的奇怪行为” 重置索引还是更改选择时触发的SelectedInexChanged 事件?如果是第一个,则上下文阻止条目选择,它用作下拉列表中的分隔符。对我来说,这很明显是控件中的错误。
    • @Rekshino ... ”...然后上下文阻止条目选择,它用作下拉列表中的分隔符。” ... ? ...如果上下文是“防止条目选择”,那么,为什么不简单地禁用组合框呢?是什么背景造成了这种特殊情况?此外,我不确定我是否同意您的术语“错误”。组合框应该做什么?它正在“选择”一个新索引,并在“完成”操作并触发其事件之前被踢出。
    • 如果您愿意,可以将其称为“错误”,但是,如果组合框在选择更改过程中失去焦点,设计师必须决定如何处理。他们选择保留“当前”选定的值。不是错误,只是控件在操作过程中失去焦点时的简单决定。设计师必须选择一个值而不是另一个值。您所说的“错误”更多是用户问题。正确使用控件,问题就解决了。
    • 只有一个/几个条目必须被禁用而不是完整的组合框。 “简单的决定” - 如果发生更改,不触发事件?如果所选索引发生更改,则控件是否具有触发SelectedIndexChanged 的焦点并不重要,例如以编程方式。
    • @Rekshino... “只有一个/几个条目必须被禁用而不是完整的组合框。” ...然后过滤组合框项目以仅在用户单击时显示您想要的项目在组合框上。
    猜你喜欢
    • 1970-01-01
    • 2011-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-21
    • 2021-08-08
    • 1970-01-01
    相关资源
    最近更新 更多