繁体   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