Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
跨线程操作无效VB.NET_Vb.net_Multithreading - Fatal编程技术网

跨线程操作无效VB.NET

跨线程操作无效VB.NET,vb.net,multithreading,Vb.net,Multithreading,我环顾了一下网站,发现与此主题相关的问题是针对C#(我维护的应用程序是用VB.NET编写的),因此如果我忽略了一个问题,我深表歉意 这里是我调用线程的地方: Private Sub saveBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles saveBtn.Click If Not LoadedFilePath = String.Empty Then Dim oTrd

我环顾了一下网站,发现与此主题相关的问题是针对C#(我维护的应用程序是用VB.NET编写的),因此如果我忽略了一个问题,我深表歉意

这里是我调用线程的地方:

Private Sub saveBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles saveBtn.Click
    If Not LoadedFilePath = String.Empty Then
        Dim oTrd = New Threading.Thread(AddressOf SaveData)
        oTrd.Start()
    End If
End Sub
以下是方法:

Private Sub SaveData()
    SaveData(LoadedFilePath)
End Sub
Private Sub SaveData(ByVal filepath As String)
    If InvokeRequired Then
        Me.Invoke(New MethodInvoker(AddressOf SaveData))
    End If
    Try
        Me.Cursor = Cursors.WaitCursor
        Dim oSettings As New SettingsClass(filepath)
        Dim oEnc As New AES
        With oSettings
            //' Code removed for brevity
        End With
        oEnc = Nothing
        oSettings.SaveSettings()
        savedLbl.Visible = True
        If SavedTimeout IsNot Nothing Then
            Try
                SavedTimeout.StopEvent()
            Catch
            End Try
        End If
        SavedTimeout = New TimedEvent(Now.AddSeconds(5))
        SavedTimeout.StartEvent()
        Me.Cursor = Cursors.Default
    Catch ex As Exception
        MsgBox(ex.Message)
    End Try
End Sub

save函数工作得很好,但是当程序试图将光标切换回默认值时,会出现跨线程错误。如何解决此问题?

您启动了一个不允许在用户界面中调用的帮助程序线程。您只能从UI线程本身设置光标

要实现这一点,您必须从助手线程触发一个事件,该事件告诉UI线程您的工作已经完成,它可以将光标设置回原位,或者通过调用UI线程来执行此操作:

private void ResetCursor()
{
    this.Cursor = Cursor.Default;
}

private delegate void UpdateCursor();
private void SaveData()
{
    //Do your work here
    if(this.InvokeRequired)
    {
        this.Invoke(new UpdateCursor(ResetCursor));
    }
    else
    {
        ResetCursor();
    }
}

在所有者(GUI)线程中调用方法的方式是错误的。如果需要调用,则不应执行方法中的其余代码。如果您这样做,您将在GUI线程和后台线程中执行它,并且当您尝试从后台线程访问GUI元素时,您将得到跨线程错误

调用应如下所示:

Private Sub SaveData(ByVal filepath As String)
   If InvokeRequired Then
      Me.Invoke(New MethodInvoker(AddressOf SaveData))
   Else
      ... the actual code
   End If
End Sub

但是为什么要在后台线程中启动该方法,而它必须在GUI线程中调用自身?

在多线程Windows窗体应用程序中,从创建控件的线程以外的任何线程调用控件上的方法或属性都是非法的。所有跨线程调用必须使用control.Invoke或control.BeginInvoke方法显式封送到创建控件的线程(通常是主线程)

以下是一个网页,可用于帮助您解决此问题:

C#


VB.NET

此网页具有从单独线程访问表单控件所需的精简代码:

哇,哈哈,我真不敢相信我忘了其他的……一天结束了!谢谢你提供的解决方案:)@Anders:我个人认为我不需要
Else
,只需在
Me.Invoke()之后添加一个
Return
,就可以阻止该方法进一步执行。通过减少嵌套,它有助于保持代码易于阅读。@yoooder:另一方面,如果该方法只有一个退出点,则更容易遵循结构。我认为这两种方法在客观上都不比另一种好。我建议不要使用递归,而是编写一个包装函数:
Sub SaveData(…params..)如果需要调用,则调用(Sub(…params..)savedataalreadyonuthread(…params..)否则savedataalreadyonuthread(…params..)End If End Sub
--另外--
Private子savedataalreadyonuthread(…params..)…执行实际工作。。结束子项
。这对于任何新程序员来说都更容易快速理解。特别是,不言而喻的是,工作总是只完成一次。然而递归版本需要花费更多的精力。注意:编写包装的另一种方法是
Sub SaveData(…params..),如果需要调用,则调用((MethodInvoker)委托{savedataalreadyonuthread(…params..)}或者savedataalreadyonuthread(…params..)如果End-If-End-Sub
那就简单了一点-不必像我在之前的评论中那样重复
.params..
。如果不明显的话,在最初的帖子中,它将是
文件路径作为字符串
,我说
.params..
s是我说“无论什么”的方式。