[英]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.