区分用户更改 Checkbox.Checked 值还是以编程方式更改

Posted

技术标签:

【中文标题】区分用户更改 Checkbox.Checked 值还是以编程方式更改【英文标题】:Differentiate between a user changing the Checkbox.Checked value, or it programmatically changing 【发布时间】:2013-10-30 07:34:22 【问题描述】:

我看到复选框有一个 CheckedChanged 事件。是否可以通过编程方式或用户实际检查复选框来判断它是否已更改?

我有一个大网格,用户可以在其中输入过滤器,或者使用复选框来提供常用过滤参数的“快速过滤器”。然后说他们去通过文本框修改过滤器,我正在检查是否应该以编程方式(取消)检查 CheckBox 控件,以便它反映文本框中的过滤器。

    private void genericCheckbox_CheckedChanged(object sender, EventArgs e)
    
        UpdateFilter();
    

    private void UpdateFilter()
    
        if (gdcSVNDefaultView.RowCount == 0)
            return;

        gdcSVNDefaultView.ActiveFilterString = BuildTableFilter();
        gdcSVNDefaultView.BestFitColumns();
    

    private void gdcSVNDefaultView_ColumnFilterChanged(object sender, EventArgs e)
    
        lblTotalFileCount.Text = gdcSVNDefaultView.RowCount.ToString();

        if (gdcSVNDefaultView.ActiveFilterString.Contains("Normal"))
            cheNormalFiles.Checked = true;
        else
            cheNormalFiles.Checked = false;

        if (gdcSVNDefaultView.ActiveFilterString.Contains("bin") || 
            gdcSVNDefaultView.ActiveFilterString.Contains("obj"))
            cheBinObjFolders.Checked = true;
        else
            cheBinObjFolders.Checked = false;
    

通过一些非常简单的测试,这似乎可以按我的意愿工作。但我担心存在某种“无限循环”情况,其中 ColumnFilterChanged 事件将触发,因为在 CheckedChanged 事件发生时调用了 UpdateFilter 方法,这反过来可能导致 CheckedChange 再次发生,因为 ColumnFilterChanged 操纵了复选框。

【问题讨论】:

【参考方案1】:

为此使用flag 是可以的:

bool suppressCheckedChanged;
private void gdcSVNDefaultView_ColumnFilterChanged(object sender, EventArgs e)

   suppressCheckedChanged = true;
   //.... your own code
   //....
   suppressCheckedChanged = false;

private void genericCheckbox_CheckedChanged(object sender, EventArgs e)

    if(suppressCheckedChanged) return;
    UpdateFilter();

更新

使用flag是我认为最好的方式(最简洁方便)。然而,在 CheckBox.cs 的内部实现 的一些搜索之后,我发现使用了内部字段 checkStateChecked 属性只是为了方便而设计的。 CheckedChanged 事件在 CheckState 属性的设置器中引发。因此,通过修改checkState 字段,我们绕过了CheckedChanged 事件引发器。因为checkState这个字段不是公开的,所以我们必须使用Reflection来改变它的值。这就是为什么这段代码比使用flag 有点长的原因。 这是给你的代码,请注意,这只是一个参考,以广泛了解这个问题,正如我所说的使用flag更简洁,代码也连贯:

//Use this extension method for convenience
public static class CheckBoxExtension 
  public static void SetChecked(this CheckBox chBox, bool check)
    typeof(CheckBox).GetField("checkState", BindingFlags.NonPublic |
                                            BindingFlags.Instance)
                    .SetValue(chBox, check ? CheckState.Checked : 
                                             CheckState.Unchecked);
    chBox.Invalidate();
  

//then you can use the SetChecked method like this:
checkBox1.SetChecked(true);//instead of checkBox1.Checked = true;
checkBox1.SetChecked(false);//instead of checkBox1.Checked = false;

【讨论】:

嗯,这个想法在我脑海中浮现,但似乎太简单了。谢谢。 哈哈,我不知道。这是其中一件看起来太明显和容易的事情,我不禁认为这不是正确/最好的方式。也许我只是倾向于把事情复杂化? @sab669 using flag 不是某种变通方法,它是一种在编程中经常使用的技术,它是straight way。关键是当您以编程方式更改值(Checked)时,如果您想通知该更改不应因此触发其他地方的其他代码,您可以显式标记一些标志,其他代码将使用该标志作为 条件来执行。另一种方法是检测用户的实际更改Checked 由用户通过ClickDoubleClick 更改,因此您可以处理这些事件而不是CheckedChanged 似乎自从回答了这个问题后,CheckState 方法已被公开,这意味着它与Checked 方法一样易于使用,但不会引发CheckedChanged 事件。 【参考方案2】:

我可能会分离然后重新附加处理程序,例如

private void gdcSVNDefaultView_ColumnFilterChanged(object sender, EventArgs e)

    cheNormalFiles.CheckedChanged -= genericCheckbox_CheckedChanged;
    cheBinObjFolders.CheckedChanged -= genericCheckbox_CheckedChanged;

    // do stuff...

    cheNormalFiles.CheckedChanged += genericCheckbox_CheckedChanged;
    cheBinObjFolders.CheckedChanged += genericCheckbox_CheckedChanged;

【讨论】:

太好了,谢谢。虽然 King King 的回答有点短,但我认为我的老板我更赞成这个。 完美。谢谢!【参考方案3】:

一般而言,您可以使用 Click 事件 CheckBoxName_Click,它仅在用户单击复选框时调用(而不是当您从代码中设置复选框选中属性时),正如事件名称所暗示的那样。

【讨论】:

这真的很好用!所有其他答案都更加复杂。谢谢! 这正是我所需要的。两种不同的函数,用于改变复选框状态的两种不同方式。 x_CheckChanged 也会在表单加载时触发,而 _Click 不会。 这会响应鼠标点击和空格键。令人兴奋!

以上是关于区分用户更改 Checkbox.Checked 值还是以编程方式更改的主要内容,如果未能解决你的问题,请参考以下文章

获取每个勾选的checkbox中的value值

checkbox radio select 选中总结

jQuery对checkbox的各种操作

如何控制 某checkbox 不可被选中

Input类型是checkbox时checked属性获取

表单的一些操作(checkbox radio select)