IsHandleCreated和InvokeRequired的顺序

DTI*_*att 3 .net c# multithreading winforms

我有以下代码,我看到它写了两种不同的方式.我只是好奇这两种方式中的哪一种更好的做法:

if (this.IsDisposed) return;

if (this.IsHandleCreated)
{
    if (this.InvokeRequired)
    {
        this.Invoke(action);
    }
    else
    {
        action();
    }
}

log.Error("Control handle was not created, therefore associated action was not executed.");
Run Code Online (Sandbox Code Playgroud)

if (this.InvokeRequired)
{
    this.Invoke(action);
}
else    
{
    if (this.IsDisposed) return;

    if (!this.IsHandleCreated)
    {
         log.Error("Control handle was not created, therefore associated action was not executed.");
         return;
    } 

    action();
}
Run Code Online (Sandbox Code Playgroud)

我主要关心的是需要控件有一个句柄的动作所产生的问题,而这些问题并非显而易见.如果我要做这样的事情,它似乎通过确保控件在执行操作之前具有句柄来解决我的问题.思考?

if (control.InvokeRequired)
{
     control.Invoke(action);
}
else
{
    if (control.IsDisposed) return;

    if (!control.IsHandleCreated)
    {
        // Force a handle to be created to prevent any issues.
        log.Debug("Forcing a new handle to be created before invoking action.");
        var handle = control.Handle;
    }

    action();
}
Run Code Online (Sandbox Code Playgroud)

FMM*_*FMM 11

你总是应该同时检查IsDisposedIsHandleCreated检查前InvokeRequired.这是一个令人抓狂的场景,我花了很多时间掌握.

以下是控件可以处于的状态:

  • :控件存在,但尚未创建其句柄.在这种情况下,IsDisposed == false,IsHandleCreated == false,但InvokeRequired == false 不管是什么主题,你用它来称呼它.如果您信任InvokeRequired未经测试(或了解其他方式)的结果是否已创建句柄以及控件是否已被释放,您可能会意外地导致创建与错误线程相关联的句柄,这会使您的应用程序崩溃.(更新)此状态实际上仅适用于控件是尚未创建句柄的表单(或其子代).
  • 实时:控件存在,其句柄已创建.这是一个简单的场景,没什么奇怪的.
  • 处理:这类似于上面的"新"状态,但是IsDisposed == true.再一次,InvokeRequired会骗你,给你带来痛苦.

正确的方法是:

if(control.IsDisposed || (!control.IsHandleCreated && !control.FindForm().IsHandleCreated))
{
    // some exceptional condition:
    // handle in whatever way is appropriate for your app
    return;
}

if(control.InvokeRequired)
{
    control.Invoke(action);
}
else
{
    action();
}
Run Code Online (Sandbox Code Playgroud)

补充说明

在.Net 2.0(和3.x)中,这更容易被吸引.InvokeRequired现在将遍历控件层次结构以确定是否已创建任何祖先控件的句柄,并验证它是在哪个线程上创建的.但是,如果控件位于从未显示过的表单上,则会产生相同的危险.以前(在2.0 - 3.5中),InvokeRequired没有走控制层次,导致更多的灾难机会.