我正在使用 VB.NET 4.8.1 我创建了一个函数 InvokeIfNecessary(action),它检查它是否在 UI 线程上运行,如果没有,则调用主窗体。
Public Sub InvokeIfNecessary(act As Action)
If IsUIThread() Then
act()
Else
Application.OpenForms(0).Invoke(act)
End If
End Sub
因为它运行得非常好,所以我开始用这个简单的函数替换我困惑的 .InvokeRequired 和其他检查。但是我刚刚收到错误“跨线程操作无效:从创建它的线程以外的线程访问控制'PB_ItemImage'。”
下面的代码在 _img.Visible=false 时失败。我之前已暂停执行以确认它正在 UI 线程中运行。该变量引用了我在设计器中创建的 PictureBox,因此显然它也应该位于 UI 线程中。 (我还确认该函数不在 UI 线程上,因此它正在使用 Invoke 函数。)
Public Function ImgDisplayFromFile(ByRef img As PictureBox, imgFileName As String, Optional safe As Boolean = False)
Dim _img = img
If Not _img.IsDisposed Then InvokeIfNecessary(Sub()
MsgBox(IsUIThread()) 'This confirmed True
MsgBox(_img.InvokeRequired()) 'This is also true??
_img.Visible = False
DoOtherStuff()
End Sub)
End Function
这在其他地方一直有效。有什么不同会导致此错误?是否有某种原因导致我不应该在 OpenForms(0) 上调用?为什么 _img.InvokeRequired 在 Invoke 函数中为 true?
这是作为 Form.Load 事件的一部分在下载图像文件的任务内执行的。
埃德。添加 IsUIThread(),它检查主窗体是否需要在所有 UI 控件都在同一线程上的假设下调用:
Public Function IsUIThread() As Boolean
If Application.OpenForms.Count = 0 Then Return Nothing
Return Not Application.OpenForms(0).InvokeRequired
End Function
最佳答案
以下示例展示了如何编写扩展方法来执行您想要执行的操作:
Imports System.Runtime.CompilerServices
Public Module ControlExtensions
<Extension>
Public Sub InvokeIfRequired(source As Control, method As Action)
If source.InvokeRequired Then
source.Invoke(method)
Else
method()
End If
End Sub
End Module
然后你可以像这样使用它:
Public Sub ImgDisplayFromFile(img As PictureBox, imgFileName As String, Optional safe As Boolean = False)
Dim _img = img
If Not _img.IsDisposed Then _img.InvokeIfRequired(Sub()
_img.Visible = False
DoOtherStuff()
End Sub)
End Sub
关于.net - 在 Invoke() 内部运行时,跨线程操作对表单控件无效 - .NET,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76010581/