【问题标题】:Handling Cross Thread Exception in Vb.Net Forms处理 Vb.Net 表单中的跨线程异常
【发布时间】:2014-05-23 15:39:32
【问题描述】:

我有一个 Windows 窗体,我在其上声明了自定义控件(标签、面板文本框),问题是我正在本地线程中加载该控件的图像,但有些图片没有从网络流中下载,因此出现异常,现在我在 Catch 块中设置图像属性 Nothing,并尝试设置其他 UI 面板属性,但它会引发异常,

例外:

“跨线程操作无效:控件“XXXXXXXXXX”从创建它的线程以外的线程访问。”

如果发生异常,请告诉我设置属性的最简单方法,以便我可以设置其他控件的属性。

【问题讨论】:

    标签: vb.net multithreading winforms user-controls


    【解决方案1】:

    基本上,您不会触摸在辅助线程上执行的方法中的控件。仅 UI 线程上的触摸控件。你通常可以这样做:

    myPictureBox.Image = myImage
    

    你现在写一个这样的方法:

    Private Sub SetPictureBoxImage(img As Image)
        If myPictureBox.InvokeRequired Then
            myPictureBox.BeginInvoke(New Action(Of Image)(AddressOf SetPictureBoxImage), img)
        Else
            myPictureBox.Image = img
        End If
    End Sub
    

    然后在辅助线程上调用它而不是直接设置 Image 属性:

    SetPictureBoxImage(myImage)
    

    请注意,无论是在 UI 线程还是辅助线程上调用该方法都会成功,因此无论您是否知道自己在辅助线程上,都可以调用它。

    Check this out 了解更多信息。

    编辑

    Private Sub UpdateUI(img As Image, visible As Boolean)
        If Me.InvokeRequired Then
            Me.BeginInvoke(New Action(Of Image, Boolean)(AddressOf UpdateUI), img, visible)
        Else
            myPictureBox.Image = img
            myPanel.Visible = visible
        End If
    End Sub
    

    请注意,我使用了表单的 InvokeRequired 和 Invoke 成员,而不是特定的控件。实际上,只要它们属于同一个 UI 线程,它们属于哪个表单或控件并不重要,但对我来说,如果只有一个或使用表单,则使用相同的控件进行更新似乎是合乎逻辑的。

    另请注意,委托的签名会更改以匹配方法的签名,以便它们具有相同数量和类型的参数。

    【讨论】:

    • 好的,很好,但是我也必须将两个面板设置为可见,我该怎么做?,你能给我提示吗?
    • @DareDevil - 将您需要在 GUI 线程上完成的所有操作放在方法的 Else 部分中(将方法重命名为 UpdatePanelsUpdateView 可能是明智的)就是这样.
    • 您可以在一种方法中对任意数量的控件进行任意数量的更改。如果您需要同时对 UI 进行大量更新,那么您应该将它们全部放在同一个方法中。如果您需要在不同时间进行更新,则使用不同的方法。例如,您可以编写另一个方法SetPanelVisible,它的作用基本相同,但使用 Panel 控件的 Visible 属性而不是 PictureBox 控件的 Image 属性。如果你想一起做这一切,然后用一种方法把它们放在一起。我在上面添加了另一个代码示例。
    • 给我时间写吧! >:(
    • 让我试试自己的朋友
    【解决方案2】:

    我已经在这个函数中完成了 UI 更改:MethodInvoker

    Try
      'Code that was throwing exception here 
    Catch ex As Exception
            Me.Invoke(New MethodInvoker(Sub() 
            'All UI changes made here
            End Sub))
    End Try
    

    【讨论】:

    • 这是一个糟糕的选择。使用异常来控制执行流程总是不好的。如果您在拨打电话之前测试InvokeRequired - 正如您应该做的那样 - 那么您知道您需要拨打Invoke 而不会引发异常。如果这样做是合理的,您应该始终避免抛出异常。它们应该只发生在真正的特殊情况下,如果您知道您将从辅助线程访问控件,那么这样做并没有什么特别之处。
    【解决方案3】:
    Control.CheckForIllegalCrossThreadCalls = False
    

    将允许您在执行中更改您的文本框、标签等...

    【讨论】:

    • 这将防止引发此特定异常,但这并不意味着这样做是安全的。默认情况下不允许跨线程操作,因为有些会失败,而且很难知道哪些会失败,所以最安全的是不做。
    猜你喜欢
    • 1970-01-01
    • 2012-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-10
    • 2013-10-06
    • 2014-03-23
    相关资源
    最近更新 更多