这个 BeginInvoke(Sub()) 是做什么的?

What does this BeginInvoke(Sub()) do?

我遇到了以下代码:

    Public Sub fun_imageCallback(ByVal data As IntPtr, ByVal rows As Integer, ByVal cols As Integer, ByVal channels As Integer, ByVal timestamp As Long)


        'Console.WriteLine(rows + " " + cols + " " + channels);
        imageMutex.WaitOne()
        If imageCamera IsNot Nothing Then
            imageCamera.Dispose()
        End If

        imageCamera = New Bitmap(cols, rows, channels * cols, PixelFormat.Format8bppIndexed, data)

        ' The default palette has strange colours, not grayscale
        Dim pal As ColorPalette = imageCamera.Palette
        For i As Integer = 0 To 255
            pal.Entries(i) = Color.FromArgb(i, i, i)
        Next
        imageCamera.Palette = pal
        imageMutex.ReleaseMutex()

        If Me.InvokeRequired Then

            Me.BeginInvoke(
        Sub()
            imageMutex.WaitOne()

            pbCamera.Image = DirectCast(imageCamera.Clone(), Bitmap)
            imageMutex.ReleaseMutex()
        End Sub
    )
        End If

    End Sub

我不明白以下 4 行是做什么的:

    If Me.InvokeRequired Then

        Me.BeginInvoke(
    Sub()
        imageMutex.WaitOne()

如何阅读?

谢谢!

我建议您先阅读 this 了解一些背景知识。

InvokeRequired 属性 的要点是确定您当前是否在拥有指定控件的线程上执行。 InvokeRequiredFalse 当你在创建控件的线程上获取它时 True 在每个其他线程上。一般来说,所有控件都在同一个线程上创建 - 启动应用程序的线程 - 这就是为什么它通常被称为 UI 线程。

如果您在创建控件的线程上执行,那么直接访问该控件的其他成员是安全的。如果您在不同的线程上,则需要在拥有的线程上调用方法,否则可能会发生不好的事情。 InvokeBeginInvoke 方法在创建控件的线程上执行方法调用。 Invoke 等待调用完成,而 BeginInvoke returns 立即,代码继续在当前线程上执行,而被调用的方法在 UI 线程上执行。

在你的情况下,重要的部分是:

pbCamera.Image = DirectCast(imageCamera.Clone(), Bitmap)

这是访问 PictureBoxImage 属性,因此必须在 UI 线程上完成。该代码测试表单的 InvokeRequired 属性,如果是 False,则表示当前代码未在 UI 线程上执行,因此不安全直接访问 Image 属性。 BeginInvoke 方法将在 UI 线程上执行指定的 Lambda 表达式,从而可以安全地访问其中的 Image 属性。

调用 InvokeBeginInvoke 时,您可以通过提供委托来指定要执行的方法。委托是引用方法的对象。可以使用 AddressOf 运算符创建常规命名方法的委托,这是我在本答案开头链接到的示例中大多数情况下所做的。 Lambda 表达式是另一种为匿名方法创建委托的方法。该代码就像编写一个包含此代码的命名方法:

imageMutex.WaitOne()
pbCamera.Image = DirectCast(imageCamera.Clone(), Bitmap)
imageMutex.ReleaseMutex()

然后使用 AddressOf 为该方法创建委托。它的工作方式是 InvokeBeginInvoke 方法在后台发挥它们的魔力,将上下文切换到 UI 线程,然后它们执行委托在该线程上引用的方法.

如果您不确定代表如何工作或可以工作,您可能有兴趣了解他们是事件背后的魔法。事件基本上是委托的集合。考虑 ButtonClick 事件。您在单击 Button 时希望在您的表单中编写一个方法。 Button 是如何执行该方法的?注册事件处理程序实际上是创建一个引用该方法的委托并将其添加到该事件的集合中。当 Button 引发事件时,它基本上遍历委托集合并调用每个委托。