Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vb.net/17.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
.net vb net update UI控件来自单独的线程事件_.net_Vb.net_Multithreading_Winforms_Winscp - Fatal编程技术网

.net vb net update UI控件来自单独的线程事件

.net vb net update UI控件来自单独的线程事件,.net,vb.net,multithreading,winforms,winscp,.net,Vb.net,Multithreading,Winforms,Winscp,我有一个名为SFTPConnectorManager.vb的类,负责管理到服务器的FTP连接。我有一个Form1.vb类,它是主要的GUI。我想更新位于Form1上的ProgressBar,以显示文件传输的进度。负责启动与FTP服务器连接的功能是在一个新线程上启动的,这允许form1不会被冻结,这很好,但是对我来说,挑战是能够更新进度条,这对我来说根本不起作用 我的尝试/做法: 使用委托从单独的线程更新UI 使用后台工作程序并使用它的进度更改事件,我想我可能在这里了解了一些事情,但后来我想起,U

我有一个名为SFTPConnectorManager.vb的类,负责管理到服务器的FTP连接。我有一个Form1.vb类,它是主要的GUI。我想更新位于Form1上的ProgressBar,以显示文件传输的进度。负责启动与FTP服务器连接的功能是在一个新线程上启动的,这允许form1不会被冻结,这很好,但是对我来说,挑战是能够更新进度条,这对我来说根本不起作用

我的尝试/做法:

  • 使用委托从单独的线程更新UI
  • 使用后台工作程序并使用它的进度更改事件,我想我可能在这里了解了一些事情,但后来我想起,UI的更新需要在文件传输事件期间发生,特别是SessionFileTransferProgress,而不是在我引发进度更改事件时发生
  • 阅读了超过20页的关于多线程和事件处理的文档,我想还是不理解 我需要做什么:

  • 更新进度条UI控件,在文件传输过程中更新,它不需要冻结UI,因此需要在单独的线程上运行(我相信到目前为止已经实现了这一点)
  • 我正在使用的代码:

  • Form1.vb

     Public Sub sub1(ByVal x As Integer, y As Integer)
        StatusLabel2.Text = "Connected"
        ProgressBar1.Maximum = ProgressBar1.Maximum + x
        ProgressBar1.Value = ProgressBar1.Value + y
    
    End Sub
    
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles StartBtn.Click
        '    If (BackgroundWorker1.IsBusy) <> True Then
        '        BackgroundWorker1.RunWorkerAsync()
        '    End If
    
        'Call Xml reader To Get respective values And store them into Class Property
    
        Dim oConnect = New SFTPConnectorManager
        Dim oXmlRead As XmlReader = XmlReader.Create("D:\dale_documents\projects\programming\vbnet\remote_data_backup\sftp_backup\settings.xml")
    
        While (oXmlRead.Read())
    
            Dim eType = oXmlRead.NodeType
    
            If (eType = XmlNodeType.Element) Then
    
                If (oXmlRead.Name = "HostName") Then
                    oConnect.HostName = oXmlRead.ReadInnerXml.ToString
                End If
    
                If (oXmlRead.Name = "UserName") Then
                    oConnect.UserName = oXmlRead.ReadInnerXml.ToString
                End If
    
                If (oXmlRead.Name = "Password") Then
                    oConnect.Password = oXmlRead.ReadInnerXml.ToString
                End If
    
                If (oXmlRead.Name = "Port") Then
                    oConnect.Port = oXmlRead.ReadInnerXml.ToString
                End If
    
                If (oXmlRead.Name = "Protocol") Then
                    oConnect.ProtocolSelection = oXmlRead.ReadInnerXml.ToString
                End If
    
                If (oXmlRead.Name = "FTPMode") Then
                    oConnect.FtpModeSelection = oXmlRead.ReadInnerXml.ToString
                End If
    
                If (oXmlRead.Name = "SSHFingerPrint") Then
                    oConnect.SSHKey = oXmlRead.ReadInnerXml.ToString
                End If
    
                If (oXmlRead.Name = "Remotepath") Then
                    oConnect.RemotePath = oXmlRead.ReadInnerXml.ToString
                End If
    
                If (oXmlRead.Name = "Localpath") Then
                    oConnect.LocalPath = oXmlRead.ReadInnerXml.ToString
                End If
            End If
    
        End While
    
        Dim eProtocolOptions = oConnect.ProtocolSelection
        Dim sUserName = oConnect.UserName
        Dim sHostName = oConnect.HostName
        Dim sPassword = oConnect.Password
        Dim sSSHKey = oConnect.SSHKey
        Dim iPort = oConnect.Port
        Dim sRemotePath = oConnect.RemotePath
        Dim sLocalPath = oConnect.LocalPath
        Dim bFlag = oConnect.bFlag
    
    
        Dim asOptions = New String() {eProtocolOptions, sHostName, sUserName, iPort, sPassword, sSSHKey, sRemotePath, sLocalPath}
    
        oConnect.TestThread(asOptions)
    
    因此,您可能会看到,我尝试使用委托,我对此做了大量的阅读,我相信这就是我需要从单独的线程更新UI元素的原因,但我显然误解了它,因为我无法在自己的项目中实现该概念。UI更改需要在SessionFileTransferProgress事件期间发生


    请各位朋友,我对此束手无策,这是我最后的救赎恩典,如果我不能理解和实施这些概念,我想我将无法继续学习编程。

    这里有一个简单的例子来说明这些概念。它有一个类,该类有一些长时间运行(sic)活动,希望向UI报告进度。您需要一个包含两个按钮、一个进度条和一个文本框的表单。希望这在概念上有所帮助

    Public Class Form1
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            ProgressBar1.Value = 0
            Dim foo As New SomeClass(New Action(AddressOf showProg))
            foo.SimulateActivity() 'long running
            Button2.Select()
        End Sub
    
        Public Sub showProg()
            If Me.InvokeRequired Then ' on the UI?
                Me.Invoke(Sub() showProg()) ' no, run this on the UI
            Else
                ProgressBar1.Increment(1) ' yes, on the UI
            End If
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            'test if UI available while long running
            'press button 2 while long running to confirm UI
            TextBox1.Text = ProgressBar1.Value.ToString
        End Sub
    End Class
    
    Public Class SomeClass
    
        Private _action As Action
        Public Sub New(progress As Action)
            Me._action = progress
        End Sub
    
        Public Sub SimulateActivity()
            'runs on thread
            Dim t As Task
            t = Task.Run(Sub()
                             For x As Integer = 1 To 100
                                 Me._action()
                                 Threading.Thread.Sleep(50)
                             Next
                         End Sub)
        End Sub
    End Class
    

    您的代码看起来基本正常。它做错了什么?oConnect.TestThread(asOptions)这个函数在主窗体中调用,它在一个单独的线程上运行FTP连接,我这样做是为了在文件传输期间UI不会冻结。在代码中,我可以看到正在将值分配给指定的控件,但它们没有反映在UI上,因此出现了一些问题,我真的不确定是什么问题。现在,如果您查看SFTPConnectorManager.vb,您将看到StartConnectionThread,如果阅读此函数,您将看到一行显示AddHandler oSession.FileTransferProgress,AddressOf SessionFileTransferProgress。这句话基本上是“在执行函数时执行这段代码,在本例中,在调用oSession.GetFiles时运行指定的函数)。我的想法是,我可以使用这一点来更新进度条,当操作在与UI相同的线程上启动时,它可以完美地工作,但我们不希望这样,因为我们希望主UI保持响应。因此,面临的挑战是在文件传输过程中从单独的线程更新UI控件。的可能副本不使用
    BeginInvoke()
    ,而不调用
    EndInvoke()
    。您将得到内存和线程泄漏。@VisualIncent-来自“如果需要,您可以调用EndInvoke从委托中检索返回值,但这不是必需的。”我想这还不清楚,但FWIW,我会编辑我的答案来解决问题。就像一只带骨头的狗一样,我不能让它离开。。。我能找到的最权威的答案是,@VisualEvent在使用BeginInvoke而不是Invoke时发生了一些有趣的事情,如果我在线程操作开始时使用BeginInvoke,它会在UI上造成很多口吃,但是在后台线程工作时,仅使用Invoke似乎可以创建平滑的UI动画。。。导致上述问题的两种方法之间的区别是什么?或者我的代码很糟糕。。
    Public Class Form1
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            ProgressBar1.Value = 0
            Dim foo As New SomeClass(New Action(AddressOf showProg))
            foo.SimulateActivity() 'long running
            Button2.Select()
        End Sub
    
        Public Sub showProg()
            If Me.InvokeRequired Then ' on the UI?
                Me.Invoke(Sub() showProg()) ' no, run this on the UI
            Else
                ProgressBar1.Increment(1) ' yes, on the UI
            End If
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            'test if UI available while long running
            'press button 2 while long running to confirm UI
            TextBox1.Text = ProgressBar1.Value.ToString
        End Sub
    End Class
    
    Public Class SomeClass
    
        Private _action As Action
        Public Sub New(progress As Action)
            Me._action = progress
        End Sub
    
        Public Sub SimulateActivity()
            'runs on thread
            Dim t As Task
            t = Task.Run(Sub()
                             For x As Integer = 1 To 100
                                 Me._action()
                                 Threading.Thread.Sleep(50)
                             Next
                         End Sub)
        End Sub
    End Class