区分用户更改 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 的内部实现 的一些搜索之后,我发现使用了内部字段 checkState。 Checked
属性只是为了方便而设计的。 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 usingflag
不是某种变通方法,它是一种在编程中经常使用的技术,它是straight way
。关键是当您以编程方式更改值(Checked
)时,如果您想通知该更改不应因此触发其他地方的其他代码,您可以显式标记一些标志,其他代码将使用该标志作为 条件来执行。另一种方法是检测用户的实际更改,Checked
由用户通过Click
和DoubleClick
更改,因此您可以处理这些事件而不是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 值还是以编程方式更改的主要内容,如果未能解决你的问题,请参考以下文章