1

给定

Action closeLoadingAction = new Action(() =>
{
  loadingForm.Close();
  #region - may need to put into second Action
  panelOnMainForm.Controls.AddRange(physdocControls.ToList<Control>().ToArray());
  if (Handle != IntPtr.Zero)
    User32DLL.SetForegroundWindow(this.Handle);//Handle is a property of the mainForm.
  #endregion
});

有时即使我检查了所需的调用,我也会处理未创建的异常。

if(loadingForm.InvokeRequired)
   loadingForm.Invoke(closeLoadingAction);
else
   closeLoadingAction();

加载表单与主表单在同一线程上运行。您在上面看到的代码在单独的线程中运行。我怀疑我需要针对主表单再次检查调用。我需要第二次检查还是我已经安全的东西?

4

3 回答 3

2

您在上面看到的代码在单独的线程中运行

当您知道代码在另一个线程上运行时,像这样使用 InvokeRequired是一种不好的反模式。你可以用它做更多有用的事情。喜欢:

if (!loadingForm.InvokeRequired) {
    throw new InvalidOperationException("Threading race detected");
}
loadingForm.Invoke(closeLoadingAction);

或者如果您打算在加载表单的 Load 事件触发之前启动加载线程,则更实用:

while (!loadingForm.InvokeRequired) Thread.Sleep(50);
loadingForm.Invoke(closeLoadingAction);

或者只是以正确的方式进行操作并让表单的 Load 事件启动线程。

于 2012-11-06T05:02:09.417 回答
1

听起来像是为创建的句柄loadingForm和对 的调用之间的竞争loadingForm.Close()

解决此问题的一种方法是在事件触发时启动包含您的.Invoke/.Close代码的线程。loadingForm.HandleCreated

private void loadingForm_HandleCreated(object sender, EventArgs e)
{
    var t = new Thread(DoLoadingStuff);
    t.Start();
}

private void DoLoadingStuff()
{
    // ...

    if(loadingForm.InvokeRequired)
       loadingForm.Invoke(closeLoadingAction);
    else
       closeLoadingAction();
}
于 2012-11-06T05:05:08.223 回答
1

如果在您尝试Invoke委托之前未显示或关闭表单,您应该只获得那些“未创建句柄”异常。没有足够的代码来确定是否是这种情况,所以如果我在你的鞋子里,我会尝试确定Closed在方法实际被调用之前是否正在调用加载表单的(因为那是调用者)事件。

InvokeRequired因为两个表单都在同一个线程上,所以只检查加载表单的属性就应该是安全的。虽然一般来说,如果你要在主窗体上操作,你应该检查那个窗体的InvokeRequired属性。同样,如果您要对加载表单进行操作(如Close上面调用),您应该检查加载表单的InvokeRequired属性。上面你正在改变panelOnMainForm,所以我会检查它是否完全安全,但我认为没有必要。

于 2012-11-06T02:18:31.913 回答