簡體   English   中英

區分用戶更改 Checkbox.Checked 值,還是以編程方式更改

[英]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();
}

UPDATE

使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM