在WinForm的进度条上显示WinSCP .NET程序集传输进度

时间:2015-10-08 10:00:06

标签: vb.net winforms winscp winscp-net

有一些主要表单,我从FTP调用文件下载。当我提出这个操作时,我希望看到新的表单ShowDialog和它上面的进度条同时显示,然后显示进度并关闭新表单并返回主表单。然而,我的代码正在工作,当它将处理时,我的主窗体冻结,然后在新窗体出现然后关闭时。我想纠正的是显示这个新表格在执行过程后立即显示。你能看看并告诉我什么是错的吗?

这是我的主要形式下载过程:

Dim pro As New FrmProgressBarWinscp(WinScp, myremotePicturePath, ladujZdjeciaPath, True)

FrmProgressBarWinscp如下:

Public Class FrmProgressBarWinscp

    Property _winScp As WinScpOperation
    Property _remotePicture As String
    Property _ladujZdjecia As String
    Property _removesource As String

    Public Sub New()
        InitializeComponent()
    End Sub

    Sub New(winscp As WinScpOperation, remotePicture As String, ladujzdjecia As String, removesource As Boolean)
        ' This call is required by the designer.
        InitializeComponent()
        ' Add any initialization after the InitializeComponent() call.
        _winScp = winscp
        _remotePicture = remotePicture
        _ladujZdjecia = ladujzdjecia
        _removesource = removesource
        ShowDialog()
    End Sub

    Sub Run()

        Try
            Cursor = Cursors.WaitCursor
            _winScp.GetFile(_remotePicture, _ladujZdjecia, _removesource)
            ProgressBar1.Minimum = 0
            ProgressBar1.Maximum = 1
            ProgressBar1.Value = 0
            Do
                ProgressBar1.Value = WinScpOperation._lastProgress
                ProgressBar1.Refresh()
            Loop Until ProgressBar1.Value = 1
            Cursor = Cursors.Default
            'Close()

        Catch ex As Exception

        Finally
            If _winScp IsNot Nothing Then
                _winScp.SessionDispose()
            End If

            System.Threading.Thread.Sleep(10000)
            Close()
        End Try

    End Sub

    Private Sub FrmProgressBarWinscp_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Run()
    End Sub
End Class

Winscp我自己的类并使用了方法:

...
Function GetFile(source As String, destination As String, Optional removeSource As Boolean = False)
    Dim result As Boolean = True
    Try

        session.GetFiles(source, destination, removeSource).Check()

    Catch ex As Exception
        result = False
    End Try
    Return result
End Function

Private Shared Sub SessionFileTransferProgress(sender As Object, e As FileTransferProgressEventArgs)
    'Print transfer progress
    _lastProgress = e.FileProgress

End Sub

Public Shared _lastProgress As Integer

...

进一步讨论nr 3:

Main form:
 Dim tsk As Task(Of Boolean) = Task.Factory.StartNew(Of Boolean)(Function()
                                                                                                Return WinScp.GetFile(myremotePicturePath, ladujZdjeciaPath, True)

                                                                                            End Function)


                            Dim forma As New FrmProgressBar
                            forma.ShowDialog()

进度条表格

Public Class FrmProgressBar

    Public Sub New()
        InitializeComponent()
    End Sub
    Sub Run()
        Try
            Do
                ProgressBar1.Value = WinScpOperation._lastProgress
                ProgressBar1.Refresh()
            Loop Until ProgressBar1.Value = 1
            Cursor = Cursors.Default

        Catch ex As Exception
        Finally
            MsgBox("before sleep")
            System.Threading.Thread.Sleep(10000)
            MsgBox("after sleep sleep")
            Close()
        End Try
    End Sub

    Private Sub FrmProgressBarWinscp_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Run()
    End Sub
End Class

点nr。 4:

  Dim tsk As Task(Of Boolean) = Task.Factory.StartNew(Of Boolean)(Function()
                                                                                                Return WinScp.GetFile(myremotePicturePath, ladujZdjeciaPath, True)

                                                                                            End Function)


                            Dim pic As New Waiting
                            pic.ShowDialog()

                            Task.WaitAll(tsk)
                            pic.Close()

第5点:

 Dim pic As New Waiting
                            pic.ShowDialog()
                            Dim tsk As Task = Task.Factory.StartNew(Sub() WinScp.GetFile(myremotePicturePath, ladujZdjeciaPath, pic, True))




                            Task.WaitAll(tsk)
                            'pic.Close()

在其他一些类中(也许在此方法被放入不同类之前未提及 - 我的自定义类)

Public Function GetFile(source As String, destination As String, formclose As InvokeCloseForm, Optional removeSource As Boolean = False) As Boolean
        Dim result As Boolean = True
        Try
            session.GetFiles(source, destination, removeSource).Check()
        Catch ex As Exception
            result = False
        End Try
        formclose.RUn()
        Return result
    End Function

接口:

Public Interface InvokeCloseForm
    Sub RUn()
End Interface

等待表格:

Public Class Waiting
    Implements InvokeCloseForm

    Public Sub RUn() Implements InvokeCloseForm.RUn
        Me.Close()
    End Sub
End Class

1 个答案:

答案 0 :(得分:1)

阻止中的Session.GetFiles method

这意味着它只在转移完成后返回。

解决方案是:

  • 在单独的线程中运行WinSCP传输(Session.GetFiles),而不是阻止GUI线程。

    请参阅WinForm Application UI Hangs during Long-Running Operation

  • 处理Session.FileTransferProgress event

    虽然请注意事件处理程序将在后台线程上调用,因此您无法直接从处理程序更新进度条。您必须使用Control.Invoke来确保在GUI线程上更新进度条。

    请参阅How to update the GUI from another thread in C#?

  • 一个简单的实现就像:

    Public Class ProgressDialog1
    
        Private Sub ProgressDialog1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            ' Run download on a separate thread
            ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf Download))
        End Sub
    
        Private Sub Download(stateInfo As Object)
            ' Setup session options
            Dim mySessionOptions As New SessionOptions
            With mySessionOptions
                ... 
            End With
    
            Using mySession As Session = New Session
                AddHandler mySession.FileTransferProgress, AddressOf SessionFileTransferProgress
    
                ' Connect
                mySession.Open(mySessionOptions)
    
                mySession.GetFiles(<Source>, <Destination>).Check()
            End Using
    
            ' Close form (invoked on GUI thread)
            Invoke(New Action(Sub() Close()))
        End Sub
    
        Private Sub SessionFileTransferProgress(sender As Object, e As FileTransferProgressEventArgs)
            ' Update progress bar (on GUI thread)
            ProgressBar1.Invoke(New Action(Of Double)(AddressOf UpdateProgress), e.OverallProgress)
        End Sub
    
        Private Sub UpdateProgress(progress As Double)
            ProgressBar1.Value = progress * 100
        End Sub
    End Class
    
  • 如果您想阻止用户进行某些操作,您可能希望在操作期间禁用进度表单(或其部分)。

    使用表单或控件的.Enabled属性。

更容易,但是hacky且通常不推荐的解决方案是从现有的Application.DoEvents处理程序中调用SessionFileTransferProgress方法。

当然,您还必须从SessionFileTransferProgress更新进度条。

Private Shared Sub SessionFileTransferProgress(sender As Object, e As FileTransferProgressEventArgs)
    'Print transfer progress
    ProgressBar1.Value = e.FileProgress
    Application.DoEvents
End Sub

进度条的.Minimum.Maximum必须在Session.GetFiles之前设置。

但不要那样做!这是一种错误的做法。

然而,您需要以与上述正确解决方案相同的方式禁用表单/控件。