VB.NET委托和调用 - 有人可以向我解释这些吗?

时间:2013-06-27 04:15:00

标签: vb.net delegates backgroundworker invoke

我是线程世界的新手,但我正在处理的应用程序的一些方面要求我使用BackgroundWorker控件来防止UI在执行某些文件操作时冻结。

我要做的是从BackgroundWorker中更新几个表单标签。从来没有使用过此之前我很快发现我无法访问未在同一个线程中创建的控件,因此经过一些研究后我实现了以下代码,似乎可以使一切工作:

Private Delegate Sub DelegateUpdateStatus(ByVal statusText As String, ByRef currentFile As String)

Private Sub UpdateStatus(ByVal statusText As String, ByVal currentFile As String)

    If InvokeRequired Then
        Invoke(Sub() LblStatus.Text = statusText)
        Invoke(Sub() LblCurrentFile.Text = currentFile)
    Else
        LblStatus.Text = statusText
        LblCurrentFile.Text = currentFile
    End If

End Sub
但是,事情是,我不知道这个代码在做什么,或者为什么需要它。

我做过一些研究,但我没有做过任何真正的工作,而且我读过的大多数文章都假设了一些先验知识。

我希望了解的三个主要内容:

  • 为什么需要此代码(例如,为什么无法直接从BackgroundWorker访问控件)
  • 代表是什么,何时需要使用
  • Invoke方法的功能,以及我使用InvokeRequired检查的内容

如上所述,线程仍然是一个非常外国的概念,所以任何简单的英语答案都会非常有用 - 谢谢!

编辑:感谢大家到目前为止的回复。我已经做了一些进一步的阅读,我想知道我是否会采用正确的方法。我使用BackgroundWorker的原因是为了确保在我执行文件操作时UI保持响应。问题是,我仍然需要等到BackgroundWorker完成它的工作,所以我可以返回一个指示操作成功的布尔值。有办法解决这个问题,但是从我的阅读中,不得不等待BackgroundWorker完成它的工作就是首先要破坏使用它的目的。那么,阻止UI锁定的最佳方法是什么?

3 个答案:

答案 0 :(得分:12)

好的,到目前为止做得很好。

让我们从第1点开始。

来自How to: Make Thread-Safe Calls to Windows Forms Controls

  

如果使用多线程来提高Windows的性能   表单应用程序,您必须确保拨打电话   以线程安全的方式控制。

     

对Windows窗体控件的访问本质上不是线程安全的。如果你   有两个或多个线程来操纵控件的状态,它是   可能迫使控件进入不一致状态。

因此,正如您所看到的,您需要确保在更改控件的状态时,它是以线程安全的方式完成的。

现在,属性Control.InvokeRequired检查您正在执行的代码是否与最初创建该控件的代码位于不同的线程上。

如果是,我们需要一些方法来调用原始线程上的代码。

因此,您需要使用Control.Invoke Method 在原始线程上执行此类代码。

  

在拥有控件底层的线程上执行委托   窗把手。

现在问题是,您需要告诉该线程它应该执行什么,这是使用delegate完成的。

  

表示委托,它是引用a的数据结构   静态方法或类实例及其实例方法   类。

现在,我建议的最后一件事是你看看代表,匿名代表,匿名方法和Lamda表达之间的区别。

答案 1 :(得分:3)

InvokeRequired问'我是否在正确的主题上?',如果是这样的话,继续,否则我需要一个委托 - 在你的代码中你会看到一个lambda Sub

 Invoke(Sub() LblStatus.Text = statusText)

另一种方法是将结果导向diff子例程(委托已经越过正确的线程),但是在这里我们能够在Invoke方法中运行一个Sub - 只是更简单这样做的方法。

每次使用单独的线程进行异步工作时都需要委托。

Invoke - MSDN

答案 2 :(得分:3)

  1. BackgroundWorker是另一种拥有线程并从中进行线程安全调用的方法。 在ProgressChangedRunWorkerCompleted,您可以对UI进行线程安全调用

  2. 委托只是参考方法

  3. Control.Invoke(代表)

      

    在拥有控件的线程上执行指定的委托       底层窗口句柄。

    Control.InvokeRequired

      

    获取一个值,该值指示调用者在对控件进行方法调用时是否必须调用invoke方法,因为调用者位于不同的线程上    而不是创建控件的那个。

    为什么我们需要所有这些东西。 从msdn文件中可以看出:

      

    如果你有两个或多个线程来操纵控件的状态,   可以强制控制进入不一致状态。   其他与线程相关的错误也是可能的,例如竞争条件和   死锁。确保访问您的控件非常重要   以线程安全的方式执行。

         

    因此,出于安全原因,我们必须实施这一点,否则我们的工人   线程和UI线程都可以尝试一次访问数据成员,   它会对我们的应用造成严重破坏。因此,而不是禁用   它,你的应用程序有可能崩溃的可能性   应该更好地使用线程安全模式。