区分用户更改 Checkbox.Checked 值,还是以编程方式更改
本文关键字:方式更 编程 Checked 用户 Checkbox | 更新日期: 2023-09-27 18:36:20
我看到复选框有一个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 操作复选框。
我可能会分离然后重新附加处理程序,例如
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;
}
为此目的使用 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
属性的 setter 中引发。因此,通过修改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;
仅在用户单击复选框时调用(而不是在从代码中设置复选框选中属性时调用),如事件名称所示。
有点死线程,但我最近不得不解决这个问题,我利用复选框上的 Focused
属性来收集用户是否按下它或它是否以编程方式触发。
我相信您的用例需要发生的所有事情都是使用查看Focused
属性的条件包装UpdateFilter()
调用:
private void genericCheckbox_CheckedChanged(object sender, EventArgs e)
{
// Only update filter if the checkbox was triggered by the user
if (((CheckBox)sender).Focused)
{
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;
}