[英]Differentiate between a user changing the Checkbox.Checked value, or it programmatically changing
我看到复选框有一个 CheckedChanged 事件。 是否可以判断它是通过编程方式更改的,还是由用户实际选中复选框更改的?
我有一个很大的网格,用户可以在其中输入过滤器,或者使用复选框作为一种提供通用过滤参数的“快速过滤器”。 然后说他们 go 并通过文本框修改过滤器,我正在检查是否应该以编程方式(取消)检查 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;
}
通过一些非常简单的测试,这似乎就像我想要的那样工作。 但我担心会出现某种“无限循环”情况,因为在 CheckedChanged 事件发生时调用了 UpdateFilter 方法,因此 ColumnFilterChanged 事件将被触发,这又可能导致 CheckedChange 再次发生,因为 ColumnFilterChanged 操作复选框。
为此目的使用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;
我可能会分离然后重新连接处理程序,例如
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;
}
通常,您可以使用Click事件 CheckBoxName_Click,该事件仅在用户单击复选框时调用(而不是在您从代码中设置复选框选中属性时),如事件名称所示。
有点死线,但我最近不得不解决这个问题,我利用复选框上的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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.