我在父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;
}
其中mainForm
是MdiParent
而stopButton
是mainForm
的{{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
?
答案 0 :(得分:3)
出于这个原因,对事件处理程序使用匿名方法或lambdas是有问题的。您要添加的代理和您要删除的代理是不同的实例(尽管包含相同的代码)。 解决此问题的解决方案是保存对要添加的委托的引用,或者使用命名方法。 See this question了解详情。
但是,我会问你为什么要首先删除事件处理程序。如果要在特定进程正在进行时阻止处理程序代码运行,我宁愿禁用该按钮,然后在处理完成后重新启用它。