【问题标题】:VB.NET Delegates and Invoke - can somebody explain these to me?VB.NET 代表和调用 - 有人可以向我解释这些吗?
【发布时间】:2013-06-27 04:14:59
【问题描述】:

我是线程领域的新手,但我正在开发的应用程序的某些方面要求我使用 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 锁定的最佳方法是什么?

【问题讨论】:

    标签: vb.net delegates backgroundworker invoke


    【解决方案1】:

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

    让我们从第 1 点开始。

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

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

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

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

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

    如果是,我们需要某种方式来调用该原始线程上的代码。

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

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

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

    代表一个委托,它是一个数据结构,它引用一个 静态方法或类实例及其实例方法 类。

    现在,我要推荐的最后一件事是你看看委托、匿名委托、匿名方法和 Lamda 表达式之间的区别。

    【讨论】:

      【解决方案2】:

      InvokeRequired 询问“我在正确的线程上吗?”,如果是这样继续,否则我需要一个委托 - 在你的代码中你会看到一个 lambda Sub

       Invoke(Sub() LblStatus.Text = statusText)
      

      另一种可行的方法是将结果定向到一个 diff Sub 例程(委托已跨到正确的线程),但在这里我们能够在 Invoke 方法本身内运行一个 Sub - 只是一个更简单方法。

      只要您使用单独的线程进行异步工作,就需要委托。

      Invoke - MSDN

      【讨论】:

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

        2. Delegate 只是对方法的引用

        Control.Invoke(委托)

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

        Control.InvokeRequired

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

        以及为什么我们需要所有这些东西。 从 msdn 文档中得到了澄清:

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

        所以为了安全起见,我们必须实施这个,否则我们的工人 线程和 UI 线程可能都尝试同时访问数据成员, 它会对我们的应用程序造成严重破坏。所以而不是禁用 它并有可能导致您的应用程序崩溃,您 应该更好地使用线程安全模式。

        【讨论】:

          猜你喜欢
          • 2011-08-20
          • 1970-01-01
          • 2022-12-16
          • 2010-10-28
          • 1970-01-01
          • 2011-05-31
          • 1970-01-01
          • 1970-01-01
          • 2018-03-28
          相关资源
          最近更新 更多