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

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.");

对比
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();
}

我最关心的问题是由需要控件具有句柄的操作引起的问题,而这些问题并不是明确需要的。 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?如果我要做这样的事情,它似乎解决了我的问题,确保控件在执行操作之前有一个句柄。想法?
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();
}

最佳答案

在检查 IsDisposed 之前,您应该始终检查 IsHandleCreatedInvokeRequired 。这是一个令人抓狂的场景,我花了很多时间来掌握。

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

  • 新的 :控件存在,但其句柄尚未创建。在这种情况下, IsDisposed == falseIsHandleCreated == false ,但 InvokeRequired == false ,无论您使用什么线程将其称为 。如果您信任 InvokeRequired 的结果而没有测试(或知道其他方式)是否已创建句柄以及是否已释放控件,则可能会意外地导致创建的句柄与错误的线程相关联,并且会使您的应用程序。 ( 更新 ) 这种状态实际上只适用于控件是(或它是)句柄尚未创建的窗体的情况。
  • Live :控件存在,它的句柄被创建。这是一个简单的场景,没什么奇怪的。
  • 处置 :这类似于上面的"new"状态,但 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();
    }
    

    附加说明

    在 .Net 2.0(和 3.x)中,这更糟糕。 InvokeRequired 现在将遍历控件层次结构以确定是否已创建任何祖先控件的句柄,并验证它是在哪个线程上创建的。但是,如果控件位于从未显示过的窗体上,则同样存在危险。以前(在 2.0 - 3.5 中),InvokeRequired 不会遍历控制层次结构,从而导致更多的灾难机会。

    关于c# - IsHandleCreated 和 InvokeRequired 的顺序,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16300527/

    10-13 03:22