【问题标题】:C# GUI handle problems on closeC# GUI 处理关闭时的问题
【发布时间】:2009-04-18 02:12:03
【问题描述】:
当我在搜索完成之前关闭我的应用程序时出现 System.InvalidOperationException 错误。当我关闭 Form1_FormClosing 时,我告诉所有线程中止。在一个线程中,它调用了一个委托函数,该函数告诉表单中的一个控件更改其文本。发生这种情况时,我会收到上述异常以及“其他信息:在创建窗口句柄之前,无法在控件上调用 Invoke 或 BeginInvoke。”
我能做些什么来纠正这个问题?我可以添加一个 isClosing 标志并在更新文本之前对其进行检查,但这感觉就像是一种黑客攻击并掩盖了问题。我该如何正确解决这个问题?
【问题讨论】:
标签:
c#
multithreading
user-interface
【解决方案1】:
发生这种情况是因为托管控件正在被释放并且不再具有其句柄,但您尚未关闭窗口,因此您仍然可以看到它。
您可以创建一个函数来包装Invoke 调用,并在调用Invoke 之前检查IsHandleCreated。如果IsHandleCreated 为假,则不能调用Invoke,可以忽略调用。
public static class ControlExtensions
{
public static TResult InvokeEx<TControl, TResult>(this TControl control,
Func<TControl, TResult> func)
where TControl : Control
{
if (!control.IsHandleCreated)
return default(T);
if (control.InvokeRequired)
return (TResult)control.Invoke(func, control);
else
return func(control);
}
public static void InvokeEx<TControl>(this TControl control,
Action<TControl> action)
where TControl : Control
{
control.InvokeEx(c => { action(c); return c; });
}
}
因此,现在只需使用 InvokeEx 将线程中的任何 Invokes 包装起来,它就会在控件已被释放且不再具有句柄时进行处理。
this.InvokeEx(c => c.label1.Text = "Hello world");
【解决方案2】:
我同意 Samuel 的观点,但也会检查 IsDisposed:
void Handler()
{
if (ctrl.IsDisposed || !ctrl.IsHandleCreated) return;
if (ctrl.InvokeRequired)
Invoke(...);
else {
...
}
}