防止绕过 ComboBox 中的 SelectedIndexChanged

Posted

技术标签:

【中文标题】防止绕过 ComboBox 中的 SelectedIndexChanged【英文标题】:Prevent bypassing SelectedIndexChanged in ComboBox 【发布时间】: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;

【问题讨论】:

确实该事件被忽略:选择被修改并且焦点传递到下一个控件。任何断点都会被忽略。 @OlivierRogier 选择更改或文本更改?我们可以验证当前选择的索引吗?我们可以测试selectedItemchanged 是否被解雇了吗? 这能回答你的问题吗? WinForms ComboBox SelectedIndexChanged not firing when typing few chars followed by Alt+Down 和 ComboBox SelectionChangeCommitted event doesn't work with AutoComplete @T.S. Selected 索引已更改,而不仅仅是文本。 @OlivierRogier 谢谢你的链接,ComboBoxStyle.DropDown 可以讨论,但我得到了一个派生控制的解决方案。 【参考方案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... “只有一个/几个条目必须被禁用而不是完整的组合框。” ...然后过滤组合框项目以仅在用户单击时显示您想要的项目在组合框上。

以上是关于防止绕过 ComboBox 中的 SelectedIndexChanged的主要内容,如果未能解决你的问题,请参考以下文章

Multi-Select ComboBox 设置 Selected 属性 True

防止WPF ComboBox中的文本自动完成?

如何防止 ComboBox 中的 NewItemPlaceholder 行绑定到与 WPF 中的 DataGrid 相同的 DataTable

如何防止根设备绕过 Android 中的证书固定?

wpf里combobox怎么取数据

wpf里combobox怎么取数据