C# 事件处理程序未及时删除

C# event handler not removed in a timely manner

我有一个 Windows 基于表单的 C# 项目,其表单具有大约 30-50 个字段(文本、组合框等)。我使用一个函数为所有对象添加相同的事件处理函数:

private readonly EventHandler hProjectBecameModified;
hProjectBecameModified = new EventHandler(ProjectBecameModified);

private void AddEventHandlers()
{
    RemoveEventHandlers();

    foreach (var _list in new List<TableLayoutControlCollection> {
        tableLayoutPanelGeneral.Controls,
        tableLayoutPanelReverse.Controls,
        tableLayoutPanelBuild.Controls,
        tableLayoutPanelLocalization.Controls,
        })
    {
        foreach (var control in _list)
        {
            if (control.GetType() == typeof(ComboBox))
                (control as ComboBox).SelectedIndexChanged += hProjectBecameModified;
            else if (control.GetType() == typeof(CheckBox))
                (control as CheckBox).CheckedChanged += hProjectBecameModified;
            else if (control.GetType() == typeof(TextBox))
                (control as TextBox).TextChanged += hProjectBecameModified;
        }
    }
}

private void ProjectBecameModified(object sender, EventArgs e)
{
    m_isSelectedProjectToBeSaved = true;
    //Etc, user modified the stuff and it is to be saved
}

并且有一个 RemoveEventHandlers() 函数与 -=s 而不是 +=s 相同。请注意,我使用条件断点检查了该函数是否适用于实际控件,因此应删除处理程序。

当我以编程方式设置内容时,我会这样做:

RemoveEventHandlers();

//setting stuff, like
//textBoxManufacturer.Text = m_selectedProject.Manufacturer;

AddEventHandlers();

问题是对于某个组合框,这是行不通的:

RemoveEventHandlers();
comboBoxConfiguration.SelectedIndex = something;

将触发事件处理函数。 (请注意,它有另一个事件处理程序,有自己的 RemoveEventHandlers() 和 AddEventHandlers() )

但是,如果我写:

comboBoxConfiguration.SelectedIndexChanged -= hProjectBecameModified;
comboBoxConfiguration.SelectedIndex = something;
RemoveEventHandlers();

会起作用。 (但如果我添加更多 RemoveEventHandlers() 调用将不起作用)。

虽然实际代码现在有效,但我对它的实际工作及其原因感到担忧。

  1. 这是一个糟糕的设计吗?
  2. 不知何故这是一种赛车条件,即。 RemoveEventHandlers() 可能 运行 在不同的线程上并且没有及时删除事件处理程序? (会很奇怪)。
  3. 是否可以多次添加相同的事件处理程序从而导致问题? (不太可能)。
  4. (提供的信息够吗?)

PS 请注意,在第一条评论之后,我在 AddEventHandlers() 函数的第一行添加了 RemoveEventHandlers() 调用。

我会建议一个更简单的选项。

试试这个:

private bool _suspended = false;

void Suspend()
{
    _suspended = true;
}

void Resume()
{
    _suspended = false;
}

private void ProjectBecameModified(object sender, EventArgs e)
{
    if (!_suspended)
    {
        m_isSelectedProjectToBeSaved = true;
        //Etc, user modified the stuff and it is to be saved
    }
}

您根本不需要通过这种方式删除事件处理程序。