Различия между пользователем, изменяющим значение Checkbox.Checked, или программным изменением

Я вижу, что флажки имеют событие CheckedChanged. можно ли определить, было ли оно изменено программно или пользователем, действительно проверяющим флажок?

У меня есть большая сетка, в которой пользователь может ввести фильтр, или использовать флажки для своего рода "быстрого фильтра", который предлагает общие параметры фильтрации. Затем скажите, что они идут и меняют фильтр через текстовое поле, я проверял, должен ли я программно (un) проверять элементы управления 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 будет срабатывать из-за вызова метода UpdateFilter при возникновении события CheckedChanged, что, в свою очередь, может привести к тому, что CheckedChange произойдет снова, поскольку ColumnFilterChanged управляет флажками.

Ответы

Ответ 1

Я бы, наверное, отсоединил, а затем снова привязал обработчик, например.

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;
}

Ответ 2

Использование 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. Поэтому, изменяя поле CheckState, мы обходим CheckedChanged event raiser. Поскольку поле 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;

Ответ 3

В общем случае вы можете использовать событие Click CheckBoxName_Click, которое вызывается только тогда, когда пользователь нажимает на этот флажок (а не когда вы устанавливаете флажок checked из кода), как указывает название события.