从任务的继续方法中的事件中删除委托

时间:2012-03-13 13:46:05

标签: c# winforms delegates task task-parallel-library

我在父MDI表单上有一个'停止进程按钮'ToolStripButton。从子表单开始,我使用TPL在后台线程上启动进程,并获取任务返回状态并相应地更改UI。 “停止进程按钮”的Click事件是使用效果良好的delegate处理的。但是,我似乎无法删除它。请参阅以下代码:

private void buttonRunValid_Click(object sender, EventArgs e)
{
    // UI.
    mainForm.stopButton.Enabled = true;

    // Thread cancellation.
    cancelSource = new CancellationTokenSource();
    token = cancelSource.Token;

    // Start new parallel task and pass uiScheduler.
    Task<bool> asyncValidationTask = new Task<bool>(state => 
        asyncRunValidationProcess(uiScheduler, token, ref timeSpan), 
            "Running Validation Process");
    asyncValidationTask.Start();

    // Callback for cancellation.
    asyncValidationTask.ContinueWith(task =>
    {
        // Do some error checking with task.Status...

        // Remove delegate (back on uiThread).
        mainForm.stopButton.Click -= delegate
            {
                UtilsTPL.CancelRunningProcess(ref mainForm, asyncValidationTask, cancelSource); 
            };
        return;
    }, TaskScheduler.FromCurrentSynchronizationContext());

    // Handle the cancellation.
    mainForm.stopButton.Click += delegate 
        { 
            UtilsTPL.CancelRunningProcess(ref mainForm, asyncValidationTask, cancelSource);
        };
    return;
}

其中mainFormMdiParentstopButtonmainForm的{​​{1}}的访问者,可以触发取消/停止流程事件。

我正在尝试删除任务延续方法中的ToolStripButton,但这不起作用。我还尝试使用反射循环遍历delegate包含的所有事件:

ToolStripButton

这也行不通。如何删除FieldInfo fieldInfo = typeof(Control).GetField("EventClick", BindingFlags.Static | BindingFlags.NonPublic); object obj = fieldInfo.GetValue(_stripButton); PropertyInfo propertyInfo = _stripButton.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance); EventHandlerList list = (EventHandlerList)propertyInfo.GetValue(_stripButton, null); list.RemoveHandler(obj, list[obj]); / EventHandler

1 个答案:

答案 0 :(得分:3)

出于这个原因,对事件处理程序使用匿名方法或lambdas是有问题的。您要添加的代理和您要删除的代理是不同的实例(尽管包含相同的代码)。 解决此问题的解决方案是保存对要添加的委托的引用,或者使用命名方法。 See this question了解详情。

但是,我会问你为什么要首先删除事件处理程序。如果要在特定进程正在进行时阻止处理程序代码运行,我宁愿禁用该按钮,然后在处理完成后重新启用它。